乘积之和

Sum of Multiplied Values

我有一个相当复杂的 XML 文件,我需要使用 XSL 对其中的几个值进行加权平均。我能够完成权重的总和或值的总和,但我无法进行乘法运算。我收到一个错误:

XPTY0004: A sequence of more than one item is not allowed as the first operand of '*'

我无法分享 XML,但我已将 XML 简化为以下示例(假设有大量 foos):

<group>
<fooList>
    <foo>
        <attributeList>
            <Attribute ID="1" Weight="0.5">
                <otherParams />
            </Attribute>
        </attributeList>
        <Properties>
            <PhysicalProperties>
                <Volume Average="125" Unknown="50" />
            </PhysicalProperties>
        </Properties>
     </foo>
</fooList>
</group>

我目前尝试获取加权平均值的方法如下:

<xsl:variable name="WeightedVolume" select="sum(/group/fooList/foo[attributeList/Attribute/[@ID=$test_id]]/attributeList/Attribute/@Weight * /group/fooList/foo[attributeList/Attribute/[@ID=$test_id]]/Properties/PhysicalProperties/Volume/@Average)"/>

我知道有类似的问题可用 - 但其中大部分涉及求和和乘法 foo

<foo>
    <Weight>0.5</Weight>
    <VolumeAverage>125</VolumeAverage>
</foo>

这个 Whosebug Question 的答案很吸引我,但我似乎无法让它发挥作用。

我使用的是 Saxonica 的 Saxon-HE 9.5.1.1N,Visual Studio 2013。

已编辑 我能够为 XSL 2 工作,但需要为 XSL1 提供后备。

<xsl:variable name="WeightedVolume" select="sum(for $i in /group/FooList/foo[attributeList/Attribute[@ID=$test_id] return $i/AttributeList/Attribute/@Weight * $i/Properties/PhysicalProperties/Volume/@Average)"/>

要遵循您链接到的那个问题中的示例,您将在 XSLT 2.0/XPath 2.0 中使用它:

<xsl:variable name="FoosToCalculate"
              select="/group/fooList/foo[attributeList/Attribute/@ID = $test_id]" />
<xsl:variable name="WeightedVolume" 
              select="sum($FoosToCalculate/(attributeList/Attribute/@Weight * 
                                 Properties/PhysicalProperties/Volume/@Average)
                          )"/>

在 XSLT 1.0 中执行此求和要复杂得多,通常涉及使用递归模板或 node-set() 函数的某种表现形式。这是后者的一个例子:

<xsl:stylesheet version="1.0"
                xmlns:ex="http://exslt.org/common"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>

  <xsl:template match="/">
    <!-- determine $test_id however you need to -->
    <xsl:variable name="products">
      <xsl:for-each 
           select="/group/fooList/foo[attributeList/Attribute/@ID = $test_id]">
        <product>
          <xsl:value-of select="attributeList/Attribute/@Weight * 
                                Properties/PhysicalProperties/Volume/@Average" />
        </product>
      </xsl:for-each>
    </xsl:variable>

    <xsl:value-of select="sum(ex:node-set($products)/product)"/>
  </xsl:template>

</xsl:stylesheet>

为了完整起见,如果您想在 XSLT 1.0 中对计算量求和,可以采用三种方法:

(a) 递归:写一个递归模板,逐个处理序列中的项目,边计算边计算总数。

(b) 创建一棵 XML 树,其中计算量是节点值,然后使用 sum() 函数处理这棵树。要在单个样式表中执行此操作,您将需要 exslt:node-set() 扩展函数。

(c) 使用 XSLT 供应商提供的扩展函数,或使用供应商提供的用于调用外部函数的设施由用户编写。

在 XSLT 2.0 中,始终可以使用结构

sum(for $x in node-set return f($x))

其中 f 是计算数量的函数。