XSLT:将累积值存储在阵列之类的结构中



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,这意味着:

  1. 我们必须将每个包装中的数量与前一个兄弟姐妹"总"值进行比较。如果数量不等于任何限定总数,那么我们将其视为形成该特定容器总数的参数。

    例如:如果您看到第一个容器,则第一个容器的总价值为8(总和两个Quantites只是没有前面的兄弟姐妹)。

  2. 对于第二个容器,我们选择第一个数量为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:小心命名空间...

相关内容

  • 没有找到相关文章

最新更新