我需要在数组/列表中累积值。我无法正确填充数组中的值以获取不同的Packed Items.Please帮助。
要求是对于每个容器,检查每个Packed Item,如果数量(在当前容器中 - > Packed Item)等于任何前面兄弟中的“Total”元素。
如是;总计=数量
其他;总计=总数+数量//总计最初为0
必须对所有不同的打包项目重复此过程。打包项由输入xml中的ItemId参数唯一标识。
输入XML
<?xml version="1.0" encoding="UTF-8"?>
<Shipment xmlns="http://www.example.org">
<Container>
<ContainerID>C1</ContainerID>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>4</Quantity>
<Total>0</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>4</Quantity>
<Total>0</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>4</Quantity>
<Total>0</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>2</Quantity>
<Total>0</Total>
</PackedItem>
</Container>
<Container>
<ContainerID>C2</ContainerID>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>4</Quantity>
<Total>0</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>8</Quantity>
<Total>0</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>6</Quantity>
<Total>0</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>6</Quantity>
<Total>0</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>5</Quantity>
<Total>0</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>2</Quantity>
<Total>0</Total>
</PackedItem>
</Container>
<Container>
<ContainerID>C3</ContainerID>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>3</Quantity>
<Total>0</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>3</Quantity>
<Total>0</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>2</Quantity>
<Total>0</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>2</Quantity>
<Total>0</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>2</Quantity>
<Total>0</Total>
</PackedItem>
</Container>
</Shipment>
输出XML
<?xml version="1.0" encoding="UTF-8"?>
<Shipment xmlns="http://www.example.org">
<Container>
<ContainerID>C1</ContainerID>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>4</Quantity>
<Total>8</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>4</Quantity>
<Total>8</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>4</Quantity>
<Total>6</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>2</Quantity>
<Total>6</Total>
</PackedItem>
</Container>
<Container>
<ContainerID>C2</ContainerID>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>4</Quantity>
<Total>10</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>8</Quantity>
<Total>8</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>6</Quantity>
<Total>10</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>6</Quantity>
<Total>6</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>5</Quantity>
<Total>7</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>2</Quantity>
<Total>7</Total>
</PackedItem>
</Container>
<Container>
<ContainerID>C3</ContainerID>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>3</Quantity>
<Total>8</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>3</Quantity>
<Total>8</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>2</Quantity>
<Total>8</Total>
</PackedItem>
</Container>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>2</Quantity>
<Total>4</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>2</Quantity>
<Total>4</Total>
</PackedItem>
</Shipment>
应用于示例XML,意味着:
我们必须将每个PackedItem中的数量与前面每个兄弟“Total”值进行比较。如果数量不等于任何预先计算总数,那么我们将其视为一个参数,以形成Container中特定PackedItem的总数。 PackedItems基于其ItemID进行识别。
例如:如果你看到第一个容器,第一个容器PackedItem1(ItemID = A123)的总值将是8(两个量子的总和就像没有前面的兄弟一样)。类似地,对于第二个打包项(ItemID = A111),Total的值将为6(因为没有前面的兄弟)。所以现在我们的数组A123中应该有2条记录 - &gt; 8和A111-> 6
对于第二个容器,第一个packedItem(A123)的第一个数量是4.我们检查它是否等于同一个项目的前一个兄弟姐妹总数(即8)。由于它不相等,因此可以考虑获得总数。在第二个conatiner中进一步移动我们将不会考虑8(在项目A123中),因为它等于先前的conatiners sum。下一个PackedItem(A123)的值为6.这不等于前一个兄弟(A123)总和所以将是考虑总数。所以现在我们有4 + 6 = 10,它在第二个conatiner中形成了PackedItem A123的总和。在类似的路线上,我们必须处理PackedItem A111的数量。数量5和2将合计形成总数为7。
将对每个容器中的所有打包项重复此过程,更新数量不等于任何前一个兄弟的总和的项的总数。 PFB我正在处理的xslt(版本2.0)。
XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ex="http://www.example.org"
xmlns:ns0="http://www.example.org"
xmlns:ns1="http://www.example.org" version="2.0">
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="ex:Container"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:param name="computed.totals"></xsl:param>
<xsl:param name="curr.total"></xsl:param>
<xsl:param name="ItemID"></xsl:param>
<xsl:copy>
<xsl:apply-templates>
<xsl:with-param name="computed.totals"
select="$computed.totals"></xsl:with-param>
<xsl:with-param name="curr.total" select="$curr.total"></xsl:with-param>
<xsl:with-param name="ItemID" select="$ItemID"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="ex:Container">
<!-- A trick to initialize to an empty node-set, see http://lists.w3.org/Archives/Public/xsl-editors/2000JulSep/0068.html -->
<xsl:param name="computed.totals" select="/@empty-node-set"/>
<ex:Container>
<xsl:apply-templates>
<xsl:with-param name="computed.totals"
select="$computed.totals"></xsl:with-param>
</xsl:apply-templates>
</ex:Container>
</xsl:template>
<xsl:template match="ex:PackedItem">
<xsl:param name="computed.totals"/>
<!-- Process the current total, taking into accound the totals of preceding siblings -->
<xsl:variable name="ItemID" select="./ex:ItemID"/>
<xsl:variable name="curr.total"
select="sum(../ex:PackedItem[./ex:ItemID=$ItemID]/ex:Quantity[(($computed.totals)/MyTotal[@ItemID=$ItemID]/@value != .) or not(($computed.totals)/*)])"></xsl:variable>
<!-- Process current Container elements -->
<xsl:copy>
<xsl:apply-templates>
<xsl:with-param name="computed.totals"
select="$computed.totals"></xsl:with-param>
<xsl:with-param name="curr.total" select="$curr.total"></xsl:with-param>
<xsl:with-param name="ItemID" select="$ItemID"/>
</xsl:apply-templates>
</xsl:copy>
<!-- Process next container, with the updated list of Total already computed -->
<xsl:apply-templates select="following-sibling::ex:Container[1]">
<xsl:with-param name="computed.totals">
<xsl:copy-of select="$computed.totals"/>
<MyTotal>
<xsl:attribute name="ContainerID">
<xsl:value-of select="ex:ContainerID"/>
</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="$curr.total"/>
</xsl:attribute>
<xsl:attribute name="ItemID">
<xsl:value-of select="$ItemID"/>
</xsl:attribute>
</MyTotal>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*[starts-with(name(),'Total')]">
<xsl:param name="computed.totals"></xsl:param>
<!-- store the current total of the Container, will be used only when processing the Total -->
<xsl:param name="curr.total"></xsl:param>
<xsl:param name="ItemID"/>
<xsl:variable name="ContainerID" select="../../ns0:ContainerID"/>
<xsl:variable name="CurrentItemID" select="../ns0:ItemID"/>
<xsl:variable name="Quantity" select="../ns0:Quantity"/>
<xsl:choose>
<xsl:when test="($computed.totals)/MyTotal[@ItemID=$CurrentItemID and @value = $Quantity]">
<xsl:copy-of select="$Quantity"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="Total" namespace="http://www.example.org">
<xsl:value-of select="$curr.total"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:0)
这是一个试图实现总值计算的XSLT 2.0样式表:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.example.org"
exclude-result-prefixes="xs"
xpath-default-namespace="http://www.example.org">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:key name="cont-pack" match="Container/PackedItem" use="ItemID"/>
<xsl:template match="@* | node()" mode="#all">
<xsl:copy>
<xsl:apply-templates select="@* | node()" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Shipment">
<xsl:copy>
<xsl:apply-templates select="Container[1]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Container">
<xsl:param name="computed" as="element(Container)*" select="()"/>
<xsl:variable name="this-computed" as="element(Container)">
<xsl:choose>
<xsl:when test="not($computed)">
<xsl:apply-templates select="." mode="compute-simple"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="." mode="compute">
<xsl:with-param name="prev" select="$computed[last()]" tunnel="yes"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="not(following-sibling::Container[1])">
<xsl:copy-of select="$computed, $this-computed"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="following-sibling::Container[1]">
<xsl:with-param name="computed" select="$computed, $this-computed"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="PackedItem/Total" mode="compute-simple">
<Total changed="true">
<xsl:value-of select="sum(key('cont-pack', ../ItemID, ancestor::Container)/Quantity)"/>
</Total>
</xsl:template>
<xsl:template match="PackedItem/Total" mode="compute">
<xsl:param name="prev" as="element(Container)" tunnel="yes"/>
<xsl:variable name="prev-total" select="$prev/PackedItem[ItemID = current()/../ItemID]/Total[@changed = 'true']"/>
<Total changed="{if ($prev-total = ../Quantity) then 'false' else 'true'}">
<xsl:value-of select="sum(key('cont-pack', ../ItemID, ancestor::Container)/Quantity[not(. = $prev-total)])"/>
</Total>
</xsl:template>
</xsl:stylesheet>
当您将Saxon 9.6 HE应用于输入样本时,我会得到输出
<Shipment xmlns="http://www.example.org">
<Container>
<ContainerID>C1</ContainerID>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>4</Quantity>
<Total changed="true">8</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>4</Quantity>
<Total changed="true">8</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>4</Quantity>
<Total changed="true">6</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>2</Quantity>
<Total changed="true">6</Total>
</PackedItem>
</Container>
<Container>
<ContainerID>C2</ContainerID>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>4</Quantity>
<Total changed="true">10</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>8</Quantity>
<Total changed="false">10</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>6</Quantity>
<Total changed="true">10</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>6</Quantity>
<Total changed="false">7</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>5</Quantity>
<Total changed="true">7</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>2</Quantity>
<Total changed="true">7</Total>
</PackedItem>
</Container>
<Container>
<ContainerID>C3</ContainerID>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>3</Quantity>
<Total changed="true">8</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>3</Quantity>
<Total changed="true">8</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>2</Quantity>
<Total changed="true">8</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>2</Quantity>
<Total changed="true">4</Total>
</PackedItem>
<PackedItem>
<ItemID>A111</ItemID>
<Quantity>2</Quantity>
<Total changed="true">4</Total>
</PackedItem>
</Container>
</Shipment>
请检查是否会显示您要查找的总计的结果。我意识到属性changed="true"/"false"
不属于最终结果,但如果中间结果在总数方面很好,那么实现剥离这些属性的最后一个处理步骤并不困难:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.example.org"
exclude-result-prefixes="xs"
xpath-default-namespace="http://www.example.org">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:key name="cont-pack" match="Container/PackedItem" use="ItemID"/>
<xsl:template match="@* | node()" mode="#all">
<xsl:copy>
<xsl:apply-templates select="@* | node()" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Shipment">
<xsl:copy>
<xsl:apply-templates select="Container[1]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Container">
<xsl:param name="computed" as="element(Container)*" select="()"/>
<xsl:variable name="this-computed" as="element(Container)">
<xsl:choose>
<xsl:when test="not($computed)">
<xsl:apply-templates select="." mode="compute-simple"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="." mode="compute">
<xsl:with-param name="prev" select="$computed[last()]" tunnel="yes"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="not(following-sibling::Container[1])">
<xsl:apply-templates select="$computed, $this-computed" mode="strip"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="following-sibling::Container[1]">
<xsl:with-param name="computed" select="$computed, $this-computed"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="PackedItem/Total" mode="compute-simple">
<Total changed="true">
<xsl:value-of select="sum(key('cont-pack', ../ItemID, ancestor::Container)/Quantity)"/>
</Total>
</xsl:template>
<xsl:template match="PackedItem/Total" mode="compute">
<xsl:param name="prev" as="element(Container)" tunnel="yes"/>
<xsl:variable name="prev-total" select="$prev/PackedItem[ItemID = current()/../ItemID]/Total[@changed = 'true']"/>
<Total changed="{if ($prev-total = ../Quantity) then 'false' else 'true'}">
<xsl:value-of select="sum(key('cont-pack', ../ItemID, ancestor::Container)/Quantity[not(. = $prev-total)])"/>
</Total>
</xsl:template>
<xsl:template match="PackedItem/Total/@changed" mode="strip"/>
</xsl:stylesheet>