При работе с 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