Самозакрывающиеся теги <empty/>
и пустой элемент с начальным и конечным тегами <empty></empty>
семантически идентичны. Поэтому процессор XSLT может выводить то, что видит лучше.
Вы можете попытаться обмануть процессор, добавив пустой элемент в элементы. В этом случае это можно сделать, изменив шаблон идентификации.
<!-- Define a dummy variable with empty content -->
<xsl:variable name="empty" select="''"/>
<!-- Copy input to output, most of the time -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
<!-- Insert empty content into copied element -->
<xsl:value-of select="$empty"/>
</xsl:copy>
</xsl:template>
Или вы можете ограничить это пустыми элементами, сохранив исходный шаблон идентификации и добавив:
<!-- Identity template for empty elements -->
<xsl:template match="*[not(node())]">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
<xsl:value-of select="$empty"/>
</xsl:copy>
</xsl:template>
Функциональность зависит от процессора XSLT.
Примечание: Правильный инструмент XML не должен иметь никакого значения между самозакрывающимися тегами или пустыми элементами с начальным и конечным тегами. Поэтому, если эта разница в синтаксисе действительно вызывает у вас проблемы, вам следует пересмотреть, какие методы или инструменты вы используете или как вы их используете.
Обновление
Дерьмо. Каким-то образом я продолжал читать ваш вопрос в противоположном вам смысле (вероятно, это значит, что мне пора вздремнуть). Итак ... приведенный выше код пытается преобразовать самозакрывающиеся теги в пустые пары, тогда как вы хотели получить обратное <tag></tag>
-> <tag/>
. Извините за несоответствие, позвольте мне попробовать еще раз.
В комментарии вы сказали:
До того, как он был в новой строке и с отступом в ту же позицию, что и открывающий тег.
С точки зрения модели данных XML это означает, что узел имеет только пустой пробел в качестве дочернего содержимого. Один из способов избежать копирования этих текстовых узлов - предоставить для них пустой шаблон. Это может вызвать проблемы со смешанным контентом.
<xsl:template match="text()[normalize-space() = '']"/>
Другое возможное решение состоит в том, что когда мы сталкиваемся с пустыми элементами, мы создаем новый элемент с тем же именем, а не копируем его.
<xsl:template match="*[not(comment() | processing-instruction() | *)][normalize-space(text()) = '']">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:for-each select="@* | namespace::*">
<xsl:copy/>
</xsl:for-each>
</xsl:element>
</xsl:template>
Этот шаблон также копирует (неиспользуемые) определения пространства имен в пустые элементы, что на самом деле кажется совершенно ненужным. <xsl:for-each>
используется вместо <xsl:apply-templates>
только потому, что template match
не позволяет использовать ось namespace
. <xsl:apply-templates select="@*"/>
также работает, если вы не хотите сохранять дополнительные определения пространства имен.
Но, в конце концов, AFAIK - это обходные пути для конкретных процессоров. Когда процессор XSLT 1.0 создает пустой элемент, он может свободно выбирать, использовать ли самозакрывающийся тег или пустую пару. Кто-нибудь, пожалуйста, поправьте меня, если я ошибаюсь.