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

时间:2016-06-18 16:36:38

标签: xml xslt sum xslt-1.0 xslt-2.0

在下面的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>

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

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

不需要总结。但是,接下来的两种记录类型是&#34; ADD&#34;因此我需要总结

的值
<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]元素值并将其添加到sum。 (索引是两个,因为我们在第二个记录类型上,因为我们跳过第一个记录,并忽略了它的成本)

  4. 查找<LdgCostIn> [2]元素值并将其添加到总和中。

  5. 查找<LdgCostOut> [2]元素值并将其添加到总和中。

  6. 现在我们已经将第二条记录中的三个成本添加到总和中,然后我们转到第三个<recordType>元素并检查其值。由于该值为ADD,我们发现与第三条记录相关的3个成本。

  7. 查找<LdgCost> [3]元素值并将其添加到sum。(索引为3,因为我们在第三个recordType上)

  8. 查找<LdgCostIn> [3]元素值并将其添加到总和中。

  9. 查找<LdgCostOut> [3]元素值并将其添加到总和中。

  10. 我们不再需要处理<recordType>元素,因此我们会返回39的总和。

4 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

---为回应澄清而编辑---

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>

答案 2 :(得分:1)

所需的总和可以表示为单个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

答案 3 :(得分:0)

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

使用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处理器的功能都不同。

使用您的数据,它返回一个节点:

<total>39</total>