我需要根据兄弟节点的索引和值对 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>
然而,我不得不根据同级元素的索引来建立父子关系,而不是使用这种结构。
我手动执行此操作的方式如下:
找到第一个<recordType>
元素,检查值是ADD还是NO。由于值为 NO 我跳过这个。
找到下一个<recordType>
元素,检查值是ADD还是NO。由于值为 ADD,因此我需要找到与第二条记录相关的 3 项成本。这些成本元素保证存在并在与其 recordType 对应的索引中。
找到 <LdgCost>
[2] 个元素值并将其添加到总和中。 (索引是两个,因为我们在第二个 recordType 上,因为我们跳过了第一个并且忽略了它的成本)
求出<LdgCostIn>
[2]个元素值加到总和
求出<LdgCostOut>
[2]个元素值并加到总和
现在我们已经将第二条记录中的三个成本添加到总和中,我们继续第三个 <recordType>
元素并检查它的值。由于值为 ADD,我们找到与第三条记录关联的 3 个成本。
找到<LdgCost>
[3]个元素的值并加到sum中。(索引为三,因为我们在第三个记录类型上)
找到<LdgCostIn>
[3]个元素值并加到总和
求出<LdgCostOut>
[3]个元素值并加到总和
没有更多的 <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
在下面的 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>
然而,我不得不根据同级元素的索引来建立父子关系,而不是使用这种结构。
我手动执行此操作的方式如下:
找到第一个
<recordType>
元素,检查值是ADD还是NO。由于值为 NO 我跳过这个。找到下一个
<recordType>
元素,检查值是ADD还是NO。由于值为 ADD,因此我需要找到与第二条记录相关的 3 项成本。这些成本元素保证存在并在与其 recordType 对应的索引中。找到
<LdgCost>
[2] 个元素值并将其添加到总和中。 (索引是两个,因为我们在第二个 recordType 上,因为我们跳过了第一个并且忽略了它的成本)求出
<LdgCostIn>
[2]个元素值加到总和求出
<LdgCostOut>
[2]个元素值并加到总和现在我们已经将第二条记录中的三个成本添加到总和中,我们继续第三个
<recordType>
元素并检查它的值。由于值为 ADD,我们找到与第三条记录关联的 3 个成本。找到
<LdgCost>
[3]个元素的值并加到sum中。(索引为三,因为我们在第三个记录类型上)找到
<LdgCostIn>
[3]个元素值并加到总和求出
<LdgCostOut>
[3]个元素值并加到总和没有更多的
<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