PFB输入xml和所需的输出。
InputXML
<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>
</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>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>
</Container>
</Shipment>
DesiredOutput
<Shipment xmlns="http://www.example.org"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="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>
</Container>
<Container>
<ContainerID>C2</ContainerID>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>4</Quantity>
<Total>6</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>8</Quantity>
<Total>8</Total>
</PackedItem>
<PackedItem>
<ItemID>A123</ItemID>
<Quantity>2</Quantity>
<Total>6</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>
</Shipment>
对于每个容器,检查每个PackedItem,如果数量(在当前容器中 - > PackedItem)等于任何前面的兄弟中的“Total”元素
if yes; Total= Quantity
else; Total=Total+quantity //total is initially 0
应用于示例XML,意味着:
我们必须将每个PackedItem中的数量与前面每个兄弟“Total”值进行比较。如果数量不等于任何预先计算总数,那么我们会将其视为形成该特定容器总数的参数。
例如:如果您看到第一个容器,则第一个容器的总值将为8(两个数量的总和就像没有前面的兄弟一样)。
对于第二个容器,我们选择第一个数量为4并检查它是否等于前面的兄弟姐妹总数(即8)。由于它不相等,因此可以考虑形成总和。在第二个conatiner中进一步移动我们将不会考虑8(第二项的数量),因为它与之前的conatiners总和相同。
第三个数量2是唯一的(不等于先前的兄弟姐妹总和),因此将被视为形成总和。因此,第二个容器的最终总数将是4 + 2 = 6。
因此,对于“Total”元素中的项目(具有唯一数量),将填充值6。因此,总计6填充在第二个容器中的第一个和第三个包装物品中。
在容器中为PackedItem的其余部分运行循环,将容器中的每个数量与先前容器中累积的总数进行比较。如果我们有一个新的Quantity值,它没有进入任何前面的兄弟节点“Total”元素将该值添加到总和并填充当前容器的“Total”元素中的最终值
如果没有前面的兄弟姐妹,那么只需在PackedItems中添加所有数量,并更新“Total”元素中的最终值。请参阅下面附带的DesiredOutput示例。
我的问题是,如果我必须填充第四个容器的“总计”,我必须计算然后比较所有三个容器中的总计。我不应该每次都计算总值。我正在寻找一种方法来计算和存储这些值在数组结构中,并能够引用它们将Packeditem中的每个数量与前一个兄弟中的每个Total值进行比较。
或者我正在寻找的另一个选项是 - 如果有办法从目标树结构中读取累积值。所以我可以读取前面容器的“Total”元素中累积的内容。
我正在研究的XSLT(版本1.0)的PFB部分
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates></xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[starts-with(name(),'Total')]">
<xsl:variable name="ContainerID" select="../../ns0:ContainerID"/>
<xsl:variable name="ItemID" select="../ns0:ItemID"/>
<xsl:variable name="Quantity" select="../ns0:Quantity"/>
<xsl:element name="Total" namespace="http://www.example.org">
<xsl:call-template name="Add">
<xsl:with-param name="ContainerID" select="$ContainerID"/>
<xsl:with-param name="ItemID" select="$ItemID"/>
<xsl:with-param name="Quantity" select="$Quantity"/>
</xsl:call-template>
</xsl:element>
</xsl:template>
<xsl:template name="Add">
<xsl:param name="ContainerID" select="$ContainerID"/>
<xsl:param name="ItemID"/>
<xsl:param name="Quantity"/>
<xsl:choose>
<!-- when there are no preceding siblings. this is the first container-->
<xsl:when test="not(/ns0:Shipment/ns0:Container[./ns0:ContainerID=$ContainerID]/preceding-sibling::ns0:Container/ns0:PackedItem[./ns0:ItemID=$ItemID])">
<xsl:value-of select="sum(/ns0:Shipment/ns0:Container[./ns0:ContainerID=$ContainerID]/ns0:PackedItem[./ns0:ItemID=$ItemID]/ns0:Quantity)"/>
</xsl:when>
<xsl:otherwise>
<!-- check the total value in preceding siblings and compare them to each quantity in this container -->
<!-- problem: reading the accumulated value in Total for preceding containers. -->
</xsl:otherwise>
</xsl:choose>
</xsl:template>
任何指针/建议都会非常有用。
答案 0 :(得分:0)
这非常具有挑战性....这是我的XSLT;请注意,您的XSL处理器必须支持XSLT扩展(exslt) - 如果您正在使用Xalan或Saxon,那就没问题了。
基本上,我们必须一个接一个地处理Container,并添加有关已计算的总计的信息。这是通过递归来完成的,这是在XSLT 1.0中修改值的唯一方法。
这就是为什么你会在一开始就找到<xsl:apply-templates select="ex:Container[1]" />
而<xsl:apply-templates select="following-sibling::ex:Container[1]">
来处理下一个Container,依此类推。
与数量进行比较的前者总数是&#34;存储&#34;在computed.totals
参数中,每次处理Container时都会填充。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl"
exclude-result-prefixes="exsl"
xmlns:ex="http://www.example.org"
xmlns:ns0="http://www.example.org"
xmlns:ns1="http://www.example.org"
version="1.0">
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="ex:Container[1]" />
</xsl:copy>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:param name="computed.totals"></xsl:param>
<xsl:param name="curr.total"></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: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" />
<!-- Process the current total, taking into accound the totals of preceding siblings -->
<xsl:variable name="curr.total" select="sum(ex:PackedItem/ex:Quantity[(exsl:node-set($computed.totals)/MyTotal/@value != .) or not(exsl:node-set($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: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>
</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:variable name="ContainerID" select="../../ns0:ContainerID"/>
<xsl:variable name="ItemID" select="../ns0:ItemID"/>
<xsl:variable name="Quantity" select="../ns0:Quantity"/>
<xsl:choose>
<xsl:when test="exsl:node-set($computed.totals)/MyTotal[@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>
样式表中还有评论:如果您有其他问题,请与我联系。
您可以在此处查看它是否正常工作:http://xsltransform.net/bFDb2CH
PS:小心命名空间......