У меня есть сложные преобразования XSLT 2.0. Я пытаюсь выяснить, существует ли общий способ для обеспечения того, чтобы пустые теги не выводились. Итак ... концептуально, заключительный этап обработки, который рекурсивно удаляет все пустые теги. Я понимаю, что это может быть сделано с помощью отдельного XSLT, который ничего не делал, кроме как отфильтровывать пустые теги, но мне нужно, чтобы все это было упаковано вместе в одном.Двухфазная обработка: не выводить пустые теги из обработки фаз-1 XSLT 2.0
ответ
Это XSLT-преобразование 2.0 иллюстрирует, как многоходовых (в данном случае 2-проход) обработка может быть сделано:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*" mode="#all">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:apply-templates select="$vPass1/*" mode="non-empty"/>
</xsl:template>
<xsl:template match="text()[xs:integer(.) mod 2 eq 0]"/>
<xsl:template match="*[not(node())]" mode="non-empty"/>
</xsl:stylesheet>
при нанесении на этом XML-документе:
<nums>
<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
<num>10</num>
</nums>
Создает результирующий документ в первом проходе (который фиксируется в переменной $vPass1
), в котором все элементы <num>
с содержимым даже интуитивно понятны r удаляются из их содержимого и пусты. Затем, во втором проходе, применяемом в определенном режиме, все пустые элементы удаляются.
Результат преобразования:
<nums>
<num>01</num>
<num>03</num>
<num>05</num>
<num>07</num>
<num>09</num>
</nums>
Обратите внимание на использование режимов, а также специальные режимы #all
и #current
.
Обновление: OP теперь хочет в комментарии удалить «рекурсивно» «все узлы, у которых нет непустого потомка».
Это может быть реализовано проще без явной рекурсии. Просто измените:
<xsl:template match="*[not(node())]" mode="non-empty"/>
к:
<xsl:template match="*[not(descendant::text())]" mode="non-empty"/>
Это отвечает на общий вопрос, но есть определенная часть, которую он пропускает - рекурсивно удаляет все пустые теги ... поэтому мне просто нужно изменить «* [not (node ())]» на соответствующее выражение, которое означает все узлы, у которых нет непустого потомка. – mentics
@taotree В следующий раз лучше сформулируйте свой вопрос. :) Я думаю, что лучше сделать это новое требование отдельным вопросом - это тоже отличный вопрос. Вы можете использовать для шаблона соответствия пустого шаблона: '* [not (descendant :: text())]' –
@taotree Обновлен ответ, чтобы отразить ваше новое требование ... :) –
Отличный вопрос (+1). См. Мой ответ для подробного решения. –