我正在使用XSLT 2.0转换XML。 重要的是,输入XML中的所有文本节点都包含在生成的XML中,并且与输入中出现的顺序相同。对于元素节点,在大多数情况下,我只想更改标记的名称,或者在新节点中包装某些节点时添加一些层次结构。
对于这个问题,我想知道如何将某个标签的第一个子事件(包括)中的所有内容视为一个“单元”,直到(包括)相同标签的最后一个子事件,< em>包括文本和其他标签。与此同时,我希望能够将此次选拔之前的所有儿童视为一个单独的“单位”,并将所有选择的儿童作为另一个单独的“单位”。
我已经包含了一个我想要的虚拟例子。假设“当前节点”是<c>
,例如如果我们在<xsl:template match="//c">
。
我想在节点{{}中将所有内容(在<c>
下)从第一个<e>
节点包装到最后一个<e>
节点(包括),包括<f>
节点1}}。我还希望(仍然只在上下文<es>
中)将所有内容保留为原样,但将所有内容包装在节点<c>
之后。我希望在<after-es>
之外没有任何副作用,例如将内容移入或移出<c>
节点。
输入XML:
<c>
预期输出XML:
<a>
alfred
<b>bob</b>
charlie
<c>
dover
<d>elon</d>
fabio
<e>grant</e>
hugh
<f>illinois</f>
jacob
<e>kathy</e>
lombard
<e>
moby
<g>narwhal</g>
obi-wan
</e>
pontiac
<h>quantas</h>
rhino
</c>
xenu
<z>yoga</z>
zombie
</a>
如何做到这一点?最好使用XSLT 2.0。解决方案越简洁越好。
答案 0 :(得分:2)
这是你可以看到它的一种方式:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="c">
<xsl:variable name="nodes-before" select="node()[. << ../e[1]]"/>
<xsl:variable name="nodes-after" select="node()[. >> ../e[last()]]"/>
<xsl:copy>
<xsl:apply-templates select="$nodes-before"/>
<es>
<xsl:apply-templates select="node() except ($nodes-before|$nodes-after)"/>
</es>
<xsl:if test="$nodes-after">
<after-es>
<xsl:apply-templates select="$nodes-after"/>
</after-es>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
请注意,这里有一个潜在的假设,c
至少有一个e
孩子。
答案 1 :(得分:0)
我自己解决这个问题,在我看到@ michael.hor257k的答案之前就开始了。
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output omit-xml-declaration="yes" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="c">
<xsl:variable name="first-e" select="count(e[ 1]/preceding-sibling::node()) + 1"/>
<xsl:variable name="last-e" select="count(e[last()]/preceding-sibling::node()) + 1"/>
<xsl:copy>
<xsl:apply-templates select="e[1]/preceding-sibling::node()"/>
<es>
<xsl:apply-templates select="node()[$first-e <= position() and position() <= $last-e]"/>
</es>
<after-es>
<xsl:apply-templates select="e[last()]/following-sibling::node()"/>
</after-es>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>