XSL v1.0 和 XPath 遍历深度嵌套并递归求和所有行 [英] XSL v1.0 and XPath to Traverse Deep Nesting and Recursively Sum all Lines

查看:72
本文介绍了XSL v1.0 和 XPath 遍历深度嵌套并递归求和所有行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找其他解决方案,并尝试了各种方法,但仍然无济于事......

这里是 XML 结构...

<continueToken/><results total="15"><result recordId="16672888"><列><栏目><field>AmountNU</field><LI_Amount><![CDATA[$4,000.00]]></LI_Amount><LI_Amount_display><![CDATA[$4,000.00]]></LI_Amount_display></列></列></结果><result recordId="16672889"><列><栏目><field>AmountNU</field><LI_Amount><![CDATA[$3,000.00]]></LI_Amount><LI_Amount_display><![CDATA[$3,000.00]]></LI_Amount_display></列></列></结果><result recordId="16672890"><列><栏目><field>AmountNU</field><LI_Amount><![CDATA[$2,000.00]]></LI_Amount><LI_Amount_display><![CDATA[$2,000.00]]></LI_Amount_display></列></列></结果></结果></查询>

这是目前为止的 XSL.这只是较大脚本的一小部分,因此您会看到与当前问题无关的其他内容.

<xsl:output method="text" encoding="UTF-8" indent="no"/><xsl:template match="/"><xsl:call-template name="fixTheWidth" ><!-- 该参数是基于result/@recordId属性的每组记录的Id.这将所有记录分组到记录 ID--><xsl:with-param name="resultIndex" select="//results/result[generate-id(.) = generate-id(key('recordID', @recordId)[1])]"/></xsl:call-template></xsl:模板><!--****************************************************************************模板:fixTheWidth目的:所有魔法发生的地方******************************************************************************--><xsl:template name="fixTheWidth" match="/results"><xsl:param name="resultIndex"/><!-- 基于对记录ID 上的记录进行分组的唯一索引--><!-- 这里有更多代码,使用 $resultIndex --><!-- 字段名称:TOTAL INVOICE AMOUNT,长度 = 9 (49-57),格式:数字 --><xsl:variable name="amount"><xsl:call-template name="total"><xsl:with-param name="sum" select="number(0)"/><xsl:with-param name="startLine" select="//LI_Amount_display"/></xsl:call-template></xsl:变量><xsl:value-of select="$amount"/></xsl:template><!-- 'fixTheWidth' 模板的结尾--><!--********************************************************************************模板:总计目的:添加正在处理的所有行项目的总金额.**********************************************************************************--><xsl:template name="total" ><xsl:param name="startLine"/><xsl:param name="sum"/><xsl:param name="newSum" select="$sum + number(translate(substring-after($startLine, '$'), ',', ''))"></xsl:param><!-- 测试桩--><xsl:variable name="amount" select="number(translate(substring-after($startLine, '$'), ',', ''))"/><xsl:value-of select="number(translate(substring-after($startLine, '$'), ',', ''))"/><xsl:text>|</xsl:text><xsl:value-of select="$newSum + $amount"/><xsl:text>&#10;</xsl:text><xsl:for-each select="$startLine/ancestor::results/following-sibling::result/columns/column/LI_Amount_display"><!-- 存根 --><xsl:text>对于每个 </xsl:text><xsl:value-of select="number(translate(substring-after(., '$'), ',', ''))"/><!-- 递归求和 --><xsl:when test="position() = last()"><xsl:value-of select="$newSum"/></xsl:when><xsl:when test="$startLine/ancestor::results/following-sibling::result/columns/column/LI_Amount_display"><xsl:call-template name="total" ><xsl:with-param name="startLine" select="."/><xsl:with-param name="sum" select="$newSum"/></xsl:call-template></xsl:when></xsl:选择></xsl:for-each></xsl:模板></xsl:stylesheet>

最终结果

9000.00

换句话说,将所有 节点相加,以便将其输出到固定宽度的平面文件中.

具体问题在于total"模板中 for-each 循环中的 XPath.我还没有看到我在那个循环中,因此,select 在某种程度上是错误的......但是,好吧,这就是我在这里的原因.>

最后,它必须是 XSL 1.0 版.

如果您想进一步说明,请告诉我.

解决方案

虽然我倾向于接受 Mathias Müller 的建议,但我想展示如何使用递归命名模板来做到这一点:

XSLT 1.0

<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/><xsl:template match="/"><xsl:call-template name="sum-nodes" ><xsl:with-param name="nodes" select="query/results/result/columns/column/LI_Amount_display"/></xsl:call-template></xsl:模板><xsl:template name="sum-nodes" ><xsl:param name="nodes"/><xsl:param name="sum" select="0"/><xsl:param name="newSum" select="$sum + translate($nodes[1], '$,', '')"/><xsl:when test="count($nodes) > 1"><!-- 递归调用--><xsl:call-template name="sum-nodes" ><xsl:with-param name="nodes" select="$nodes[position() > 1]"/><xsl:with-param name="sum" select="$newSum"/></xsl:call-template></xsl:when><xsl:否则><xsl:value-of select="format-number($newSum, '#,##0.00')"/></xsl:否则></xsl:选择></xsl:模板></xsl:stylesheet>

结果:

9,000.00

I've been all over SO looking at other solutions, and tried various approaches, but still to no avial...

Here is the XML structure...

<?xml version="1.0" encoding="UTF-8"?>
<query>
    <continueToken/>
    <results total="15">
        <result recordId="16672888">
            <columns>
                <column>
                    <field>AmountNU</field>
                    <LI_Amount><![CDATA[$4,000.00]]></LI_Amount>
                    <LI_Amount_display><![CDATA[$4,000.00]]></LI_Amount_display>
                </column>
            </columns>
        </result>
        <result recordId="16672889">
            <columns>
                <column>
                    <field>AmountNU</field>
                    <LI_Amount><![CDATA[$3,000.00]]></LI_Amount>
                    <LI_Amount_display><![CDATA[$3,000.00]]></LI_Amount_display>
                </column>
            </columns>
        </result>
        <result recordId="16672890">
            <columns>
                <column>
                    <field>AmountNU</field>
                    <LI_Amount><![CDATA[$2,000.00]]></LI_Amount>
                    <LI_Amount_display><![CDATA[$2,000.00]]></LI_Amount_display>
                </column>
            </columns>
        </result>
    </results>
</query>

And here is the XSL so far. This is only a small piece of a larger script, so you will see other things in that that are tangential to the current issue.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:datetime="http://exslt.org/dates-and-times"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="datetime">
    <xsl:output method="text" encoding="UTF-8" indent="no"/>

    <xsl:template match="/">
        <xsl:call-template name="fixTheWidth" >
            <!-- This parameter is a Id for each group of records based on the result/@recordId attribute. This groups all records to the record ID-->
            <xsl:with-param name="resultIndex" select="//results/result[generate-id(.) = generate-id(key('recordID', @recordId)[1])]" />
        </xsl:call-template>
    </xsl:template>

    <!--************************************************************************ 
        TEMPLATE: fixTheWidth
        PURPOSE: Where all the magic happens 
    *************************************************************************-->
    <xsl:template name="fixTheWidth" match="/results">
        <xsl:param name="resultIndex" /> <!-- A unique index based on grouping the records on the recordID -->

        <!-- more code here, uses $resultIndex -->

        <!-- Field Name: TOTAL INVOICE AMOUNT, Length = 9 (49-57), Format: numeric -->        
        <xsl:variable name="amount">
            <xsl:call-template name="total">
                <xsl:with-param name="sum" select="number(0)" />
                <xsl:with-param name="startLine" select="//LI_Amount_display" />
            </xsl:call-template>
        </xsl:variable>        
        <xsl:value-of select="$amount" />
    </xsl:template><!-- END of 'fixTheWidth' template -->

<!--****************************************************************************
    TEMPLATE: total
    PURPOSE: Add the total amount of all line items being processed.
*****************************************************************************-->
    <xsl:template name="total" >
        <xsl:param name="startLine"/>
        <xsl:param name="sum"/>
        <xsl:param name="newSum" select="$sum + number(translate(substring-after($startLine, '$'), ',', ''))"></xsl:param>

        <!-- TEST STUB -->
        <xsl:variable name="amount" select="number(translate(substring-after($startLine, '$'), ',', ''))" />
        <xsl:value-of select="number(translate(substring-after($startLine, '$'), ',', ''))" />
        <xsl:text> | </xsl:text>        
        <xsl:value-of select="$newSum + $amount" />
        <xsl:text>&#10;</xsl:text> 

        <xsl:for-each select="$startLine/ancestor::results/following-sibling::result/columns/column/LI_Amount_display">
            <!-- STUB -->
            <xsl:text> for each </xsl:text>
            <xsl:value-of select="number(translate(substring-after(., '$'), ',', ''))" />

            <!-- Recursively Sum --> 
            <xsl:choose>
                <xsl:when test="position() = last()">
                    <xsl:value-of select="$newSum"/>
                </xsl:when>
                <xsl:when test="$startLine/ancestor::results/following-sibling::result/columns/column/LI_Amount_display">
                <xsl:call-template name="total" >
                    <xsl:with-param name="startLine" select="." />
                    <xsl:with-param name="sum" select="$newSum" />
                </xsl:call-template>
                </xsl:when>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

The end result

9000.00

In other words, sum all the <LI_Amount_display/> nodes so that it can be output into a fixed width flat file.

The specific question lies around the XPath in the for-each loop in the "total" template. I haven't yet been able to see that I'm in that loop, thus, the select is in some way wrong... but how, well, that's why I'm here.

And finally, it must be with XSL version 1.0.

Let me know if you'd like further clarification.

解决方案

While I tend to go with the suggestion made by Mathias Müller, I wanted to show how you can do this using a recursive named template:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:template match="/">
    <xsl:call-template name="sum-nodes" >
        <xsl:with-param name="nodes" select="query/results/result/columns/column/LI_Amount_display" />
    </xsl:call-template>
</xsl:template>

<xsl:template name="sum-nodes" >
    <xsl:param name="nodes"/>
    <xsl:param name="sum" select="0"/>
    <xsl:param name="newSum" select="$sum + translate($nodes[1], '$,', '')"/>
    <xsl:choose>
        <xsl:when test="count($nodes) > 1">
             <!-- recursive call --> 
            <xsl:call-template name="sum-nodes" >
                <xsl:with-param name="nodes" select="$nodes[position() > 1]" />
                <xsl:with-param name="sum" select="$newSum" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="format-number($newSum, '#,##0.00')"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

Result:

9,000.00

这篇关于XSL v1.0 和 XPath 遍历深度嵌套并递归求和所有行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆