将来自不同父节点的XML节点分组

时间:2011-03-07 15:44:49

标签: xslt

我对xslt感到沮丧,并且有一个问题,我似乎无法找到答案。我正在将转换应用于xml文件,然后使用fo将其输出到.pdf。输入文件(xml)来自计费系统,我们希望将其输出为pdf,可以作为账单邮寄给客户。我正在使用xslt 1.0并且fop正在生成pdf。我无法从2个不同的父母(CHARGES和OTHER_CHARGES)分组类似命名的节点(TAX)。这是一个例子:
(输入文件)

<BILL>
    <CHARGES PARENT_ID="123456" CUSTOMER="MR. JONES">
        <CHARGE NAME="CHARGE1" AMOUNT="10000">
            <TAXES>
                <TAX NAME="FEDERAL" AMOUNT="200"/>
                <TAX NAME="STATE" AMOUNT="50">
            </TAXES>
        </CHARGE>
    </CHARGES>
    <OTHER_CHARGES PARENT_ID="123456" CUSTOMER="MR_JONES">
        <OTHER_CHARGE NAME="OTHER_CHARGE1">
            <TAXES>
                <TAX NAME="FEDERAL" AMOUNT="150"/>
            </TAXES>
        </OTHER_CHARGE>
    </OTHER_CHARGES>
</BILL>

我想要计费的项目的总税金,以便pdf输出看起来像这样

联邦政府 - 350美元 国家 - 50美元

尽管来自不同的节点,但总税额按名称及其总数分组。我对键和分组的理解有限,但我似乎无法找到一个在脑中轻弹开关的神奇例子。

3 个答案:

答案 0 :(得分:1)

所以你可以做的(如果你必须坚持使用XSLT 1.0)是:

  • 选择变量中的所有税款

<xs:variable name="taxes" select="//TAX"/>

  • 然后选择不同的TAX名称,如下所示:

<xs:variable name="distict_taxes" select="//$taxes[not(@NAME=preceding::TAX/@NAME)"/>

  • 然后通过for-each将名称放入变量$ taxname并执行:
  • 来迭代这些不同的税

<xs:value-of select="sum(//*/TAXES/TAX[@NAME=$taxname]/@AMOUNT)"/>

希望有所帮助。

答案 1 :(得分:1)

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>
    <xsl:key name="kTaxes" match="TAX" use="@NAME"/>
    <xsl:template match="/*">
        <xsl:apply-templates select="
            */*/TAXES/TAX[generate-id() = generate-id(key('kTaxes', @NAME)[1])]
            "/>
    </xsl:template>
    <xsl:template match="TAX">
        <xsl:value-of select="@NAME"/>
        <xsl:text>: </xsl:text>
        <xsl:value-of select="sum(key('kTaxes', @NAME)/@AMOUNT)"/>
        <xsl:text>&#xa;</xsl:text>
    </xsl:template>
</xsl:stylesheet>

应用于稍微复杂的文档:

<BILL>
    <CHARGES PARENT_ID="123456" CUSTOMER="MR. JONES">
        <CHARGE NAME="CHARGE1" AMOUNT="10000">
            <TAXES>
                <TAX NAME="FEDERAL" AMOUNT="200"/>
                <TAX NAME="STATE" AMOUNT="50"/>
                <TAX NAME="HEALTH" AMOUNT="300"/>
            </TAXES>
        </CHARGE>   
    </CHARGES>
    <OTHER_CHARGES PARENT_ID="123456" CUSTOMER="MR_JONES">
        <OTHER_CHARGE NAME="OTHER_CHARGE1">
            <TAXES>
                <TAX NAME="FEDERAL" AMOUNT="150"/>
                <TAX NAME="MATERNITY" AMOUNT="150"/>
                <TAX NAME="HEALTH" AMOUNT="600"/>
            </TAXES>
        </OTHER_CHARGE>
    </OTHER_CHARGES>
</BILL>

正确的结果将是:

FEDERAL: 350
STATE: 50
HEALTH: 900
MATERNITY: 150

答案 2 :(得分:0)

如果您可以使用XSLT 2.0,请尝试以下方法:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">

    <xsl:output method="xml" indent="yes" omit-xml-declaration="no" />

    <xsl:template match="BILL">
        <report>
            <xsl:for-each-group select=".//TAX" group-by="@NAME">
                <tax>
                    <xsl:attribute name="name">
                        <xsl:value-of
                            select="current-grouping-key()" />
                    </xsl:attribute>
                    <xsl:attribute name="total">
                        <xsl:value-of 
                            select="sum(current-group()/@AMOUNT)" />
                    </xsl:attribute>
                </tax>
            </xsl:for-each-group>
        </report>
    </xsl:template>

</xsl:stylesheet>

输出

<report>
    <tax name="FEDERAL" total="350"/>
    <tax name="STATE" total="50"/>
</report>