При работе с XML/XSLT существует неприятный момент: форматирование XML-документа влияет на его структуру. В этой статье мы рассмотрим несколько примеров "граблей" и путей их обхода.
Форматирование XML-элементов
Рассмотрим XML-документ:
<test>
<item/>
<item/>
<item/>
</test>
Будет иметь следующую структуру:
Довольно странно видеть вместо трёх потомков элемента test
целых семь.
Этого можно избежать, вставив в XSLT-преобразование следующий код:
<xsl:strip-space elements="*"/>
Теперь приведённый выше XML будет восприниматься XSLT-процессором следующим образом:
Однако при этом стоит помнить, что так же будет воспринят и такой XML:
<test>
<item/>
<item> </item>
<item><![CDATA[ ]]></item>
</test>
Если вам действительно нужен пробел, то я советую писать:
<item> </item>
xsl:strip-space
имеет силу только над символами:
пробел (#x20
), возврат каретки (#xD
),
перевод строки (#xA
), знак табуляции (#x9
).
Форматирование CDATA
Рассмотрим следующий XML-документ:
<test>
<item>
<![CDATA[hello world]]>
</item>
</test>
Применим к этому документу XSLT-преобразование:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="no" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<text>
<xsl:value-of select="//test/item"/>
</text>
</xsl:template>
</xsl:stylesheet>
Вы ожидаете, что на выходе будет:
<text>hello world</text>
Но на самом деле получится:
<text>
hello world
</text>
Неожиданно и неприятно. Правильным советом здесь является использовать
функцию normalize-space
в xsl:value-of
Преобразование будет выглядеть так:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="no" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<text>
<xsl:value-of select="normalize-space(//test/item)"/>
</text>
</xsl:template>
</xsl:stylesheet>
Теперь мы получаем желаемый результат:
<text>hello world</text>
Однако, то же самое получится и для такого XML-документа:
<test>
<item>
<![CDATA[ hello world]]>
</item>
</test>
Функция normalize-space
удалит все лишние пробельные символы в TEXT-элементе.
Объединение TEXT-элементов
У XML-элемента не может быть несколько подряд идущих TEXT-элементов. Подряд идущие CDATA и строки будут объединены в один TEXT-элемент. Например, рассмотрим XML-документ:
<test>
<item><![CDATA[hello]]> <![CDATA[world]]>!</item>
</test>
Он будет иметь следующую структуру:
Заключение
Форматирования CDATA в XML легче не допускать, чем с ним бороться. В противном случае стоит использовать описанные средства.
Статья подготовлена по материалам статьи: Tricky whitespace handling in XSLT