我有这样一个XML:
<xml>
<node1>1.1</node1>
<node1>1.2</node1>
<node1>1.3</node1>
<node2>2.1</node2>
<node2>2.2</node2>
<node2>2.3</node2>
<node3>3.1</node3>
<node3>3.2</node3>
<node3>3.3</node3>
</xml>
我想得到以下输出:
线: 1.1 + 2.1 + 3.1
线: 1.2 + 2.2 + 3.2
线: 1.3 + 2.3 + 3.3
有没有办法同时迭代这些节点并跟踪我在三个列表中的每个列表中的当前位置,或者我是否必须将这些项目包装成一个更大的块并迭代块?
我正在使用 XSL 1.0。
就这么简单:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node1">
<xsl:variable name="vPos" select="position()"/>
<xsl:value-of select=". + ../node2[$vPos] + ../node3[$vPos]"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
将此转换应用于以下 XML 文档(基于提供的文档)时:
<xml>
<node1>1</node1>
<node1>2</node1>
<node1>3</node1>
<node2>4</node2>
<node2>5</node2>
<node2>6</node2>
<node3>7</node3>
<node3>8</node3>
<node3>9</node3>
</xml>
生成所需的正确结果:
12
15
18
请注意:
- 在 XSLT
1.0 和 XSLT 2.0 中,可以使用 FXSL 模板/函数
zip-with3()
。在 XPath 3.0 (XSLT 3.0) 中,将有一个标准函数
map-pairs()
,但没有map-tripples()
标准函数。可以使用此函数生成中间结果,然后再次使用它来生成最终结果。正如 Ian Roberts 所指出的,此解决方案中存在
xsl:strip-space
很重要 - 没有它,position()
函数会产生不同的结果,并且转换不会按要求执行。
我认为XSLT中没有内置的方法可以做到这一点。我想你可以通过应用MapReduce技术轻松地实现它。
我认为以下内容可以完成这项工作(与xml
元素的子元素的数量和名称无关):
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="name" match="xml/*" use="local-name()"/>
<xsl:variable name="first" select="xml/*[generate-id() = generate-id(key('name', local-name())[1])]"/>
<xsl:template match="xml">
<xsl:apply-templates select="$first[1]" mode="init"/>
</xsl:template>
<xsl:template match="xml/*" mode="init">
<xsl:apply-templates select="key('name', local-name())" mode="line"/>
</xsl:template>
<xsl:template match="xml/*" mode="line">
<xsl:variable name="pos" select="position()"/>
<xsl:text>line: </xsl:text>
<xsl:for-each select="$first">
<xsl:if test="position() > 1"><xsl:text> + </xsl:text></xsl:if>
<xsl:apply-templates select="key('name', local-name())[$pos]"/>
</xsl:for-each>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="xml/*">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>