Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Xml XSLT:在类似数组的结构中存储累积值_Xml_Xslt_Xslt 1.0 - Fatal编程技术网

Xml XSLT:在类似数组的结构中存储累积值

Xml XSLT:在类似数组的结构中存储累积值,xml,xslt,xslt-1.0,Xml,Xslt,Xslt 1.0,PFB输入xml和所需的输出 InputXML 应用于示例XML,意味着: 我们必须将每个包装中的数量与前面的每个兄弟姐妹的总价值进行比较。如果数量不等于任何一个预置总数,那么我们将考虑它作为一个参数来形成那个容器的总数。 例如:如果您看到第一个容器,第一个容器的total值将是8,因为没有前面的同级 对于第二个容器,我们选择第一个数量4,并检查它是否等于前面的兄弟姐妹总和8。由于它不相等,因此将被视为构成总和。在第二个求和器中进一步移动,我们不会考虑第二个项的8个量,因为它与先前的求和器的总和

PFB输入xml和所需的输出

InputXML

应用于示例XML,意味着:

我们必须将每个包装中的数量与前面的每个兄弟姐妹的总价值进行比较。如果数量不等于任何一个预置总数,那么我们将考虑它作为一个参数来形成那个容器的总数。 例如:如果您看到第一个容器,第一个容器的total值将是8,因为没有前面的同级


对于第二个容器,我们选择第一个数量4,并检查它是否等于前面的兄弟姐妹总和8。由于它不相等,因此将被视为构成总和。在第二个求和器中进一步移动,我们不会考虑第二个项的8个量,因为它与先前的求和器的总和是相等的。p> 第三个数量2是唯一的,不等于前面的同胞总和,因此将被视为构成总和。因此,第二个容器的最终总数为4+2=6


因此,对于在Total元素中具有唯一数量的项目,将填充值6。因此,第二个集装箱内的第1个和第3个包装项目中总共填充了6个

对容器中剩余的PackedItem运行一个循环,将容器中的每个数量与之前容器中累积的总量进行比较。如果我们的Quantity有一个新值,但它没有出现在前面的任何同级Total元素中,则将该值添加到总和中,并填充当前容器的Total元素中的最终值

如果没有前面的同级,那么只需添加PackedItems中的所有数量,并更新Total元素中的最终值。请参考下面随附的所需输出样品

我的问题是,如果我必须填充第四个容器的总数,我必须计算并比较前三个容器的总数。我不必每次都计算总值。我正在寻找一种方法来计算这些值并将其存储在一个类似数组的结构中,并且能够引用它们来比较Packeditem中的每个数量与前面同级中的每个Total值

或者我正在寻找的另一个选项是-如果有一种方法可以从目标树结构中读取累计值。因此,我可以读取之前容器的Total元素中累积的内容

PFB是我正在研究的XSLT 1.0版的一部分

<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,那么就可以了

基本上,我们必须一个接一个地处理容器,并添加有关已计算总数的信息。这是通过递归实现的,递归是XSLT1.0中修改值的唯一方法

这就是为什么您会在一开始就找到一个处理下一个容器的方法,依此类推

要与数量进行比较的前一个总数存储在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>
样式表中还有一些注释:如果您还有其他问题,请告诉我

您可以在此处检查它是否正常工作:


PS:小心名称空间…

如果我理解得很好,我们必须先计算一些总数,然后再次处理这些数据,将总数设置为每个名称空间的最终值,对吗?但是:1我在您想要的输出中没有看到容器中的任何总数2我没有看到任何第四个容器1我们必须将每个包装数据项中的数量与前面的每个同级总值进行比较。如果数量不等于任何一个汇总总数,那么我们将把它看作是形成特定容器总数的一个参数。例如:如果你看到第一个容器,第一个容器的总价值将是8个和两个数量,因为没有前面的兄弟姐妹。我们选择第一个数量是4,并检查它是否等于前面的兄弟姐妹总和8。由于它不相等,因此将被视为构成总和。在第二个求和器中进一步移动,我们不会考虑第二个项的8个量,因为它与先前的求和器总和相等。第三个数量2是唯一的,不等于前面的同胞总和,因此将被视为构成总和。因此,第二个容器的最终总数将为4+2=6。因此,对于在total元素中具有唯一数量的项目,将填充值6。因此,第二个集装箱中的第一个和第三个包装的物品中总共有6个。非常感谢您调查这个问题!我正在Jdeveloper中编写XSLT,它将与我的BPEL流程一起部署到Oracle SOA suite 11g中。我不确定它是否支持exslt。我试图编译您在Jdevel中提供的xslt解决方案
oper,但它抛出一个错误,表示转换失败:应为根元素的开始。我进一步尝试在Stylus studio中编译xslt,得到以下错误-java.lang.RuntimeException:error:在Sample.xsl:XTDE1425:的第33行找不到名为{}节点集的匹配单参数函数。没有具有本地名称节点setName的Saxon扩展函数。您提供的解决方案在xalan和saxon处理器上运行良好。但是,我们的产品不支持exslt,我们决定切换到XSL2.0。听起来不错。使用XSLT2.0,您不再需要使用扩展。是的,我们删除了节点集扩展,XSLT工作得很好。
if yes; Total= Quantity     
else; Total=Total+quantity //total is initially 0 
<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>
<?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>