【问题标题】:Summing values of recursive functions in XSLTXSLT 中递归函数的求和值
【发布时间】:2011-03-07 10:15:00
【问题描述】:

我有这样的 XML:

 <assessment name="Assessment">
  <section name="Section1">
   <item name="Item1-1"/>
   <item name="Item1-2"/>
   <item name="Item1-3"/>
   <item name="Item1-4"/>
   <item name="Item1-5"/>
  </section>
  <section name="Section2">
   <item name="Item2-1"/>
   <item name="Item2-2"/>
   <item name="Item2-3"/>
   <section name="Section2-2">
    <item name="Item2-2-1"/>
    <item name="Item2-2-2"/>
    <item name="Item2-2-3"/>
    <item name="Item2-2-4"/>
   </section>
  </section>
 </assessment>

如您所见,评估可以包含部分。一个部分可以包含部分和/或项目。

我想使用 XSLT 递归计算评估和部分中的项目数。所以,我的转换应该输出如下内容:

Assessment: 12 items
Section1:    5 items
Section2:    7 items
Section2-2:  4 items

我从这个递归 XSLT 开始:

<stylesheet version="2.0" xmlns="http://www.w3.org/1999/XSL/Transform"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <output method="text"/>

 <template match="/assessment">
  <xsl:for-each select="section">
   <xsl:call-template name="sectionCount">
   </xsl:call-template>
  </xsl:for-each>
 </template>

 <template name="sectionCount">
  <xsl:variable name="items" select="item"/>
   <xsl:for-each select="section">
     <xsl:call-template name="sectionCount">
     </xsl:call-template>
   </xsl:for-each>
  <xsl:value-of select="count($items)"/>
 </template>
</stylesheet>

我不知道该怎么做是将值传回并添加它们。这到底是怎么做到的?

【问题讨论】:

  • 好问题 (+1)。请参阅我对 XSLT 2.0 解决方案的回答,该解决方案更通用,可用于一类类似(和更复杂)的问题。 :)

标签: xslt function recursion


【解决方案1】:

回答您的问题:您将对模板的调用包装在变量声明中。

<xsl:variable name="result">
  <!-- call or apply templates here -->
  <xsl:call-template name="my-template"/>
</xsl:variable>
<!-- use the defined value: -->
<xsl:copy-of select="$result"/>

但是,在您的情况下,有一种更好的方法来获取嵌套结构中任意深度的项目总数:使用 XPath 通配符:

<xsl:value-of select="count(.//item)"/>

你可以这样使用:

<xsl:template match="assessment|section">
   <!-- output section subtotal -->
   <!-- print name : number-of-items, adapt to get the proper section name -->
   <xsl:value-of select="concat(@name, ': ', count(.//item))"/>
   <!-- recurse: sub sections will get their subtotals listed, too -->
   <xsl:apply-templates select="*"/>
</xsl:template>

【讨论】:

    【解决方案2】:

    这是一个 XSLT 2.0 解决方案

    <xsl:stylesheet version="2.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
     xmlns:my="my:my"
     >
     <xsl:output method="text"/>
     <xsl:strip-space elements="*"/>
    
        <xsl:template match="assessment|section">
          <xsl:value-of select="concat(@name, ': ', my:sumItems(.), ' items&#xA;')"/>
          <xsl:apply-templates/>
        </xsl:template>
    
        <xsl:function name="my:sumItems" as="xs:integer*">
          <xsl:param name="pNode" as="element()"/>
    
          <xsl:sequence select="count($pNode/item) + sum($pNode/section/my:sumItems(.))"/>
        </xsl:function>
    </xsl:stylesheet>
    

    当此转换应用于提供的 XML 文档时

    <assessment name="Assessment">
        <section name="Section1">
            <item name="Item1-1"/>
            <item name="Item1-2"/>
            <item name="Item1-3"/>
            <item name="Item1-4"/>
            <item name="Item1-5"/>
        </section>
        <section name="Section2">
            <item name="Item2-1"/>
            <item name="Item2-2"/>
            <item name="Item2-3"/>
            <section name="Section2-2">
                <item name="Item2-2-1"/>
                <item name="Item2-2-2"/>
                <item name="Item2-2-3"/>
                <item name="Item2-2-4"/>
            </section>
        </section>
    </assessment>
    

    产生想要的正确结果

    Assessment: 12 items
    Section1: 5 items
    Section2: 7 items
    Section2-2: 4 items
    

    虽然在这个特定问题中可以使用简单的 XPath 表达式 (count(.//item)),但这个解决方案展示了一种通用且有用的模式,用于解决不允许这种立即计算的问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-20
      • 1970-01-01
      • 1970-01-01
      • 2021-03-16
      • 2020-04-16
      • 2019-10-18
      相关资源
      最近更新 更多