我需要根据兄弟节点的索引和值对 xslt 中的某些节点求和

I need to sum certain nodes in xslt based on the index and value of sibling nodes

在下面的 xml 结构中,如果记录类型为 "ADD"

,我需要使用 xsl 对每个记录类型的成本值求和
<records> 
   ...irrelevant nodes...
   <recordType>NO</recordType>
   <recordType>ADD</recordType>
   <recordType>ADD</recordType>
   ... irrelevant nodes...
   <LdgCost>1</LdgCost>
   <LabCostIn>2</LabCostIn>
   <LabCostOut>3</LabCostOut>
   <LdgCost>4</LdgCost>
   <LabCostIn>5</LabCostIn>
   <LabCostOut>6</LabCostOut>
   <LdgCost>7</LdgCost>
   <LabCostIn>8</LabCostIn>
   <LabCostOut>9</LabCostOut>
   ...irrelevant nodes...
</records>

(记录类型的成本是与记录类型相同的索引中的以下元素)。这意味着不需要添加类型为 "NO" 的第一个位置的 recordType,因此其值

<LdgCost>1</LdgCost>
<LabCostIn>2</LabCostIn>
<LabCostOut>3</LabCostOut>

不需要求和。但是,接下来的两个记录类型是 "ADD" 因此我需要对

的值求和
<LdgCost>4</LdgCost>
<LabCostIn>5</LabCostIn>
<LabCostOut>6</LabCostOut>
<LdgCost>7</LdgCost>
<LabCostIn>8</LabCostIn>
<LabCostOut>9</LabCostOut>

并将其设置为我的总数。输出只是一个总元素

<total>39</total>

如果使用父子节点,上述xml结构所代表的逻辑结构如下

<records> 
   <record>
       <recordType>NO</recordType>
       <LdgCost>1</LdgCost>
       <LabCostIn>2</LabCostIn>
       <LabCostOut>3</LabCostOut>
   </record>
   <record>
       <recordType>ADD</recordType>
       <LdgCost>4</LdgCost>
       <LabCostIn>5</LabCostIn>
       <LabCostOut>6</LabCostOut>
   </record>
   <record>
       <recordType>ADD</recordType>
       <LdgCost>7</LdgCost>
       <LabCostIn>8</LabCostIn>
       <LabCostOut>9</LabCostOut>
   </record>
</records>

然而,我不得不根据同级元素的索引来建立父子关系,而不是使用这种结构。

我手动执行此操作的方式如下:

  1. 找到第一个<recordType>元素,检查值是ADD还是NO。由于值为 NO 我跳过这个。

  2. 找到下一个<recordType>元素,检查值是ADD还是NO。由于值为 ADD,因此我需要找到与第二条记录相关的 3 项成本。这些成本元素保证存在并在与其 recordType 对应的索引中。

  3. 找到 <LdgCost>[2] 个元素值并将其添加到总和中。 (索引是两个,因为我们在第二个 recordType 上,因为我们跳过了第一个并且忽略了它的成本)

  4. 求出<LdgCostIn>[2]个元素值加到总和

  5. 求出<LdgCostOut>[2]个元素值并加到总和

  6. 现在我们已经将第二条记录中的三个成本添加到总和中,我们继续第三个 <recordType> 元素并检查它的值。由于值为 ADD,我们找到与第三条记录关联的 3 个成本。

  7. 找到<LdgCost>[3]个元素的值并加到sum中。(索引为三,因为我们在第三个记录类型上)

  8. 找到<LdgCostIn>[3]个元素值并加到总和

  9. 求出<LdgCostOut>[3]个元素值并加到总和

  10. 没有更多的 <recordType> 元素要处理,所以我们 return 39 的总和。

--- 根据澄清进行编辑 ---

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/records">
    <xsl:variable name="i" select="index-of(recordType, 'ADD')" />
    <xsl:variable name="costs" select="LabCost | LabCostIn | LabCostOut" />
    <total>
        <xsl:copy-of select="sum($costs[(position() - 1) idiv 3 + 1 = $i])"/>
    </total>
</xsl:template>

</xsl:stylesheet>

如果您知道可以使用的元素名称

<xsl:template match="/records">
    <xsl:variable name="positions" select="index-of(recordType, 'ADD')"/>
    <total>
        <xsl:value-of select="sum(LdgCost[position() = $positions]
            | LabCostIn[position() = $positions]
            | LabCostOut[position() = $positions])"/>
    </total>
</xsl:template>

这样做可以满足您的需求:

使用 XSLT 1 和 MSXML

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
    exclude-result-prefixes="msxsl"
    >
  <xsl:output method="xml"/>
  <xsl:template match="/">
      <!-- create a set of node for all the values that need to be added -->
      <xsl:variable name="values">
        <xsl:apply-templates select="records/recordType"/>
      </xsl:variable>
        <!-- at this point $values contains a fragment with groups of
        <LdgCost>value</LdgCost>
        <LabCostIn>value</LabCostIn>
        <LabCostOut>value</LabCostOut>
        -->
        <total>
            <!-- sum up all the values -->
           <xsl:value-of select="sum(msxsl:node-set($values)/*)"/>
        </total>
  </xsl:template>

  <xsl:template match="recordType[.='ADD']">
      <!-- the index for the ADD recordType -->
      <xsl:variable name="index" select="position()"/>
      <!-- select costs using index -->
      <xsl:copy-of select="/records/LdgCost[$index]"/>
      <xsl:copy-of select="/records/LabCostIn[$index]"/>
      <xsl:copy-of select="/records/LabCostOut[$index]"/>
  </xsl:template>
</xsl:stylesheet>

我在这里使用的是节点集函数,每个 xslt 处理器都不同。

使用你的数据,returns一个节点:

<total>39</total>

所需的总和可以表示为单个 XPath 2.0 表达式。下面是两个不同的表达式:

sum(/*/*[name()=('LdgCost', 'LabCostIn', 'LabCostOut')]
           [for $vPos in ceiling(position() div 3)
             return 
               /*/recordType[$vPos] eq 'ADD']
   )

:

sum(for $vAddPositions in index-of(/*/recordType, 'ADD')
      return
        /*/*[name()=('LdgCost', 'LabCostIn', 'LabCostOut')]
               [ceiling(position() div 3) = $vAddPositions]
   )

这里是一个基于XSLT 2.0的验证(转换只是输出对这两个表达式求值的结果):

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

  <xsl:template match="/">
    <xsl:sequence select=
    "sum(/*/*[name()=('LdgCost', 'LabCostIn', 'LabCostOut')]
               [for $vPos in ceiling(position() div 3)
                 return 
                   /*/recordType[$vPos] eq 'ADD']
        )
    "/>

    =====================

    <xsl:sequence select=
    "sum(for $vAddPositions in index-of(/*/recordType, 'ADD')
          return
            /*/*[name()=('LdgCost', 'LabCostIn', 'LabCostOut')]
                   [ceiling(position() div 3) = $vAddPositions]
         )
    "/>
   </xsl:template>
</xsl:stylesheet>

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

<records> 
   ...irrelevant nodes...
    <recordType>NO</recordType>
    <recordType>ADD</recordType>
    <recordType>ADD</recordType>
   ... irrelevant nodes...
    <LdgCost>1</LdgCost>
    <LabCostIn>2</LabCostIn>
    <LabCostOut>3</LabCostOut>
    <LdgCost>4</LdgCost>
    <LabCostIn>5</LabCostIn>
    <LabCostOut>6</LabCostOut>
    <LdgCost>7</LdgCost>
    <LabCostIn>8</LabCostIn>
    <LabCostOut>9</LabCostOut>
   ...irrelevant nodes...
</records>

产生了想要的、正确的结果:

39

=====================

39