使用XSLT在XML节点上进行并行迭代

时间:2012-11-14 13:36:40

标签: xml xslt xslt-1.0

我有这种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。

3 个答案:

答案 0 :(得分:2)

这么简单

<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>&#xA;</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

请注意

  1. 在XSLT 1.0和XSLT 2.0中,可以使用 FXSL 模板/函数 zip-with3()

  2. 在XPath 3.0(XSLT 3.0)中,将有一个标准函数map-pairs(),但没有map-tripples()标准函数。可以使用此函数生成中间结果,然后再次使用它来生成最终结果。

  3. 正如Ian Roberts所指出的,xsl:strip-space在此解决方案中的存在非常重要 - 如果没有它,position()函数会产生不同的结果,并且转换不会按要求执行。< / p>

答案 1 :(得分:0)

我认为在XSLT中没有内置的方法来做到这一点。我想你可以通过应用MapReduce技术轻松实现它。

答案 2 :(得分:0)

我认为以下工作(独立于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>&#10;</xsl:text>
</xsl:template>

<xsl:template match="xml/*">
  <xsl:value-of select="."/>
</xsl:template>

</xsl:stylesheet>