XSLT 中递归函数的求和值

发布于 2024-09-07 10:42:43 字数 1639 浏览 3 评论 0原文

我有这样的 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>

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

I have XML like this:

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

As you can see, an assessment can contain sections. A section can contain sections and/or items.

I want to use XSLT to recursively count the number of items in assessments and sections. So, my transformation should output something like this:

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

I have a start with this recursive 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>

What I can't figure out how to do is pass the values back up and add them. How is this done, exactly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

醉殇 2024-09-14 10:42:43

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

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

To answer your question: you wrap the call to the template(s) in a variable declaration.

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

However there is, in your case a better way to get total number of items arbitrarily deep in the nested structure: use XPath wildcards:

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

You can use this like so:

<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>
橘虞初梦 2024-09-14 10:42:43

这是一个 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
')"/>
      <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)),此解决方案演示了一种针对不允许此类立即计算的问题的通用且有用的模式

Here is an XSLT 2.0 solution

<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
')"/>
      <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>

when this transformation is applied on the provided XML document:

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

the wanted, correct result is produced:

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

While in this particular problem one could use a straightforward XPath expression (count(.//item)), this solution demonstrates a generall and useful pattern for problems that don't allow such immediate calculation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文