Parallel iteration over XML nodes with XSLT

女生的网名这么多〃 提交于 2019-12-24 08:58:03

问题


I have an XML of this kind:

<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>

and I want to get the following output:
line: 1.1 + 2.1 + 3.1
line: 1.2 + 2.2 + 3.2
line: 1.3 + 2.3 + 3.3

Is there a way I can iterate over these nodes simultaneously and keep track of my current position in each of three lists or do I have to wrap these items into a bigger block and iterate over blocks?

I'm using XSL 1.0.


回答1:


As easy as this:

<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>

When this transformation is applied on the following XML document (based on the provided one):

<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>

the wanted, correct result is produced:

12
15
18

Do note:

  1. In XSLT 1.0 and XSLT 2.0 one can use the FXSL template/function zip-with3().

  2. In XPath 3.0 (XSLT 3.0) there will be a standard function map-pairs(), but there is no map-tripples() standard function. One can use this function to produce an intermediate result and then use it again to produce the final result.

  3. As noted by Ian Roberts, the presence of xsl:strip-space in this solution is important -- without it the position() function produces different results and the transformation doesn't perform as required.




回答2:


I don't think there is a builtin way in XSLT to do that. I guess you could implement it yourself easily by applying the MapReduce technique.




回答3:


I think the following does the job (independent of the number and names of child elements of the xml element):

<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>


来源:https://stackoverflow.com/questions/13379853/parallel-iteration-over-xml-nodes-with-xslt

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!