Вот краткое и простое (без xsl:choose
, xsl:when
и xsl:otherwise
) решение :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:param name="pParent" select="/.."/>
<xsl:copy>
<xsl:apply-templates select="node()|@*">
<xsl:with-param name="pParent" select="$pParent"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="prot">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="../prot/node">
<xsl:with-param name="pParent" select="."/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="node/text()">
<xsl:param name="pParent" select="/.."/>
<xsl:variable name="vSameParent" select=
"boolean(not((../.. | $pParent)[2]))"/>
<xsl:value-of select=
"concat(substring('-', 1 +$vSameParent),
self::node()[$vSameParent]
)
"/>
</xsl:template>
</xsl:stylesheet>
, когда это преобразование применяется кпредоставляется XML-документ :
<data>
<prot seq="AAA">
<node num="4">1345</node>
</prot>
<prot seq="BBB">
<node num="7">6666</node>
</prot>
<prot seq="CCC">
<node num="10">3e33</node>
</prot>
</data>
желаемый, правильный результат :
<data>
<prot seq="AAA">
<node num="4">1345</node>
<node num="7">-</node>
<node num="10">-</node>
</prot>
<prot seq="BBB">
<node num="4">-</node>
<node num="7">6666</node>
<node num="10">-</node>
</prot>
<prot seq="CCC">
<node num="4">-</node>
<node num="7">-</node>
<node num="10">3e33</node>
</prot>
</data>
Объяснение :
Мы используем и переопределяем модифицированную версию правила идентификации - которая принимает и передает параметр с именем $pParent
.
Параметр $pParent
содержит элемент node
, который выдал xsl:apply-templates
, частью которого является обработка текущего узла.
У нас есть два шаблона, которые переопределяют правило идентификации.Первый переопределяющий шаблон соответствует любому элементу prot
.Оно почти идентично правилу идентификации, но оно устанавливает для параметра $pParent
значимое значение (сам этот узел).
Второй переопределяющий шаблон соответствует любому текстовому узлу, который являетсяпотомок любого node
элемента.Здесь, в зависимости от того, идентифицирует ли значение $pParent
прародителя сопоставляемого текстового узла, мы выводим соответственно значение текстового узла или просто "-"
.
Решение о том, что выводить, принимается без использования каких-либо явных условных инструкций.Вместо этого мы используем функцию XPath concat()
с двумя аргументами, один из которых является непустой строкой.Чтобы убедиться в этом свойстве, мы используем логическую переменную $vSameParent
, которая указана таким образом, что ее значение равно true()
именно тогда, когда прародитель совпадающего текстового узла идентичен узлу, содержащемуся в $pParent
.Наконец, мы используем тот факт, что при использовании в качестве числа логическое значение true()
преобразуется в 1
, а логическое значение false()
преобразуется в 0
.
Обновление : Это новое решение для модифицированной проблемой OP:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kNodeByNum" match="node" use="@num"/>
<xsl:template match="node()|@*">
<xsl:param name="pNum"/>
<xsl:copy>
<xsl:apply-templates select="node()|@*">
<xsl:with-param name="pNum" select="$pNum"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="prot">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select=
"../prot/node
[generate-id()
=
generate-id(key('kNodeByNum', @num)[1])
]
">
<xsl:with-param name="pNum" select="node/@num"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="node/text()">
<xsl:param name="pNum" select="/.."/>
<xsl:variable name="vSameNum" select=
"../@num = $pNum"/>
<xsl:value-of select=
"concat(substring('-', 1 +$vSameNum),
self::node()[$vSameNum]
)
"/>
</xsl:template>
</xsl:stylesheet>
, когда это преобразование применяется к предоставленному XML-документу :
<data>
<prot seq="AAA">
<node num="4">1345</node>
</prot>
<prot seq="BBB">
<node num="7">6666</node>
</prot>
<prot seq="CCC">
<node num="10">3e33</node>
</prot>
<prot seq="DDD">
<node num="4">1345</node>
</prot>
<prot seq="EEE">
<node num="10">3e33</node>
</prot>
</data>
получен новый требуемый результат :
<data>
<prot seq="AAA">
<node num="4">1345</node>
<node num="7">-</node>
<node num="10">-</node>
</prot>
<prot seq="BBB">
<node num="4">-</node>
<node num="7">6666</node>
<node num="10">-</node>
</prot>
<prot seq="CCC">
<node num="4">-</node>
<node num="7">-</node>
<node num="10">3e33</node>
</prot>
<prot seq="DDD">
<node num="4">1345</node>
<node num="7">-</node>
<node num="10">-</node>
</prot>
<prot seq="EEE">
<node num="4">-</node>
<node num="7">-</node>
<node num="10">3e33</node>
</prot>
</data>
Объяснение : те же основные идеи, что и в исходной задаче, с добавлением мюнхенская группировка .