XSLT-递归循环基本案例

时间:2018-07-20 14:28:30

标签: xml xslt

我有一个XML输入文档:

<root>
  <MultiItem name="m1">
    <MultiItem name="m2">
      <SingleItemA name="s1A" >
        <SingleItemB name="s1B"/>
      </SingleItemA >
      <SingleItemB name="s2B" />
    </MultiItem>
    <SingleItemB name="s3B" />
    <MultiItem name="m3">
      <SingleItemA name="s2A" >
        <MultiItem name ="m4">
          <SingleItemA name="s3A"/>
        </MultiItem>
      </SingleItemA>
      <MultiItem name="m5">
        <SingleItemB name="s4B" />
        <SingleItemA name="s4A" >
          <SingleItemA name="s5A" />
        </SingleItemA>
      </MultiItem>
    </MultiItem>
  </MultiItem>
</root>

这包含<MultiItem>个节点,这些节点可以包含任意数量的<SingleItemA><SingleItemB><MultiItem>节点。还有<SingleItem>个仅包含一个节点的节点。

嵌套<MultiItem>节点的数量也没有限制,因此可能会发生以下情况:

<MultiItem>
  <MultiItem>
    <MultiItem>
      <MultiItem>
        <MultiItem>
          <MultiItem>
            <SingleItemA />
          </MultiItem>
        </MultiItem>
      </MultiItem>
    </MultiItem>
  </MultiItem>
</MultiItem>

我需要编写一个xslt模板,该模板递归地遍历所有元素,同时计算<SingleItemA>节点的数量。基于此计数,将应用其他模板。这都是更大的XSLT转换的一部分,因此apply-templates调用将无法工作。

我也只关心<MultiItem>节点中的第一级元素。如果一个<SingleItemA>节点位于另一个<SingleItemA>节点内,则我不希望它计算在内。但是,如果一个<MultiItem>节点位于另一个<MultiItem>节点内,则需要检查其中的<SingleItemA>个节点。对于上面的示例,由于<SingleItemA>个节点的名称为s1A,s2A,s4A

,因此计数为3

这是我到目前为止提出的模板,它是从与<MultiItem>之类的xsl:call template name='GetCountAndAppy.>匹配的模板中调用的,其参数计数等于零:

 <xsl:template name="GetCountAndApply">
    <xsl:param name="count"/>
    <xsl:for-each select="child::*">
      <xsl:choose>
        <xsl:when test="name() = 'MultiItem'">
          <xsl:for-each select="./*">
            <xsl:call-template name="GetCountAndApply">
              <xsl:with-param name="count" select="$count"/>
            </xsl:call-template>
          </xsl:for-each>
        </xsl:when>
        <xsl:when test="name() = 'SingleItemA'">
          <xsl:call-template name="GetCountAndApply">
            <xsl:with-param name="count" select="$count + 1"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise/> <!-- skip to next child -->
      </xsl:choose>
    </xsl:for-each>

    <xsl:if test="'HasLoopedThroughEverything[NEED A WAY TO TELL]'">
      <xsl:choose>
        <xsl:when test="$count  > 1">
          <!--Apply templates-->
        </xsl:when>
        <xsl:otherwise>
          <!--Apply different templates-->
        </xsl:otherwise>
      </xsl:choose>
    </xsl:if>
  </xsl:template>

我一直无法弄清楚是否要放入if循环中来说明没有其他可循环的情况。是否有人对如何执行此操作有任何建议,或者我在思考过程中哪里出了错。 XSLT对我来说还很新。

1 个答案:

答案 0 :(得分:1)

您实际上仍然不需要递归模板。尽管可能有更好的方法(特别是如果您可以使用XSLT 3.0),则可以尝试执行以下操作:

<xsl:variable name="ancestorCount" select="count(ancestor::SingleItemA)" />
<xsl:variable name="count" select="count(.//SingleItemA[count(ancestor::SingleItemA) = $ancestorCount])" />