我正在用测试描述解析一个巨大的单词文件,并且有节点范围的问题。Word 基本上会创建一个段落列表,我想将它们分组到一个父节点中。因此,对于每个节点“A”,我想将所有以下节点分组到下一个节点“A”到“A”中。
XSL 如何做到这一点?
示例:我已经得到:
<A/>
<ab/>
<ac/>
<A/>
<ab/>
<ac/>
但需要:
<A>
<ab/>
<ac/>
</A>
<A>
<ab/>
<ac/>
</A>
谢谢!
有一个使用键的简单且非常强大的解决方案。
这种转变:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kFollowing" match="*[not(self::A)]"
use="generate-id(preceding-sibling::A[1])"/>
<xsl:template match="/*">
<t>
<xsl:apply-templates select="A"/>
</t>
</xsl:template>
<xsl:template match="A">
<A>
<xsl:copy-of select=
"key('kFollowing',generate-id())"/>
</A>
</xsl:template>
</xsl:stylesheet>
应用于原始 XML 文档时:
<t>
<A/>
<ab/>
<ac/>
<A/>
<ab/>
<ac/>
</t>
产生想要的结果:
<t>
<A>
<ab/>
<ac/>
</A>
<A>
<ab/>
<ac/>
</A>
</t>
如果你的意思是匹配所有节点之后<A>
,但在下一个之前<A>
,我认为你可以使用这样的东西:
<xsl:template match="A">
<xsl:copy>
<!-- start of range -->
<xsl:variable name="start" select="count(preceding-sibling::*) + 1" />
<!-- end of range -->
<xsl:variable name="stop">
<xsl:choose>
<!-- either just before the next A node -->
<xsl:when test="following-sibling::A">
<xsl:value-of select="count(following-sibling::A[1]/preceding-sibling::*) + 1" />
</xsl:when>
<!-- or all the rest -->
<xsl:otherwise>
<xsl:value-of select="count(../*) + 1" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- this for debugging only -->
<xsl:attribute name="range">
<xsl:value-of select="concat($start + 1, '-', $stop - 1)" />
</xsl:attribute>
<!-- copy all nodes in the calculated range -->
<xsl:for-each select="../*[position() > $start and position() < $stop]">
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:copy>
</xsl:template>
对于您的输入:
<root>
<A />
<ab />
<ac />
<A />
<ab />
<ac />
</root>
我得到(我留下了“范围”属性以使计算可见):
<A range="2-3">
<ab />
<ac />
</A>
<A range="5-6">
<ab />
<ac />
</A>
XSLT 2.0 解决方案:
<xsl:for-each-group select="*" group-starting-with="A">
<xsl:element name="{name(current-group()[1])}">
<xsl:copy-of select="current-group()[position() gt 1]"/>
</xsl:element>
</xsl:for-each-group>