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)等于上一个兄弟姐妹中任何一个中的"总"元素
if yes; Total= Quantity
else; Total=Total+quantity //total is initially 0
应用于样品XML,这意味着:
我们必须将每个包装中的数量与前一个兄弟姐妹"总"值进行比较。如果数量不等于任何限定总数,那么我们将其视为形成该特定容器总数的参数。
例如:如果您看到第一个容器,则第一个容器的总价值为8(总和两个Quantites只是没有前面的兄弟姐妹)。
对于第二个容器,我们选择第一个数量为4,并检查它是否等于兄弟姐妹总和(8)。由于它不相等,因此将被认为形成总和。在第二个Conatiner中进一步移动,我们将不会考虑8(第二项数量),因为它是先前的conatiners总和。
第三数量2是唯一的(不等于前面的兄弟姐妹总和),因此被认为是形成总和。因此,第二个容器的最终总数为4 2 = 6。
因此,"总"元素中的项目(具有唯一数量)的值6填充了值。因此,在第二个容器中,总共有6个填充物中的第一个和第三个包装项目。
在容器中运行一个循环,以将容器中的所有数量与以前的容器中的总累积进行比较。如果我们有一个新的数量值,该值尚未在上一个兄弟姐妹" 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>
任何指示/建议都会非常有帮助。
这很具有挑战性。...这是我的XSLT;请注意,您的XSL处理器必须支持XSLT扩展名(EXSLT) - 如果您使用Xalan或Saxon,则可以。
基本上,我们必须对容器进行处理,并添加有关已经计算的总计的信息。这是通过递归完成的,这是修改XSLT 1.0中值的唯一方法。
为什么您会从一开始就找到<xsl:apply-templates select="ex:Container[1]" />
,而<xsl:apply-templates select="following-sibling::ex:Container[1]">
处理下一个容器,依此类推。
与数量进行比较的前一个总数被"存储"在computed.totals
参数中,并且每次处理容器时都会填充。
<?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:小心命名空间...