在XSLT中对连续元素进行分组

时间:2014-12-09 08:36:31

标签: xslt grouping

我是XSLT和XML的新手。我有以下XML。我想将连续的子元素分组。

<Root>
    <Child No="1" Month="0" Date="13/08/2014" Payment="100">
        <Totals/>
    </Child>
    <Child No="2" Month="1" Date="13/09/2014" Payment="100">
        <Totals/>
    </Child>
    <Child No="3" Month="2" Date="13/10/2014" Payment="200">
        <Totals/>
    </Child>
    <Child No="4" Month="3" Date="13/11/2014" Payment="300">
        <Totals/>
    </Child>
    <Child No="5" Month="4" Date="13/12/2014" Payment="300">
        <Totals/>
    </Child>
    <Child No="6" Month="5" Date="13/01/2015" Payment="100">
        <Totals/>
    </Child>
    <Child No="7" Month="6" Date="13/01/2015" Payment="100">
        <Totals/>
    </Child>
    <Child No="8" Month="7" Date="13/01/2015" Payment="100">
        <Totals/>
    </Child>
    <Child No="9" Month="8" Date="13/01/2015" Payment="100">
        <Totals/>
    </Child>
    <Child No="10" Month="9" Date="13/01/2015" Payment="100">
        <Totals/>
    </Child>
</Root>

我需要在Child[n]/Payment <> Child[n-1]/Payment使用XSLT时创建一个新的PP节点。

我期待以下结果,

<PPS>
    <PP>
        <Ps>
            <StartMonth>0</StartMonth>
            <EndMonth>1</EndMonth>
            <P>
                <Amount>100</Amount>
                <startP>1</startP>
            </P>
            <P>
                <Amount>100</Amount>
                <startP>2</startP>
            </P>
        </Ps>
    </PP>
    <PP>
        <Ps>
            <StartMonth>2</StartMonth>
            <EndMonth>2</EndMonth>
            <P>
                <Amount>200</Amount>
                <startP>3</startP>
            </P>
        </Ps>
    </PP>
    <PP>
        <Ps>
            <StartMonth>3</StartMonth>
            <EndMonth>4</EndMonth>
            <P>
                <Amount>300</Amount>
                <startP>4</startP>
            </P>
            <P>
                <Amount>300</Amount>
                <startP>5</startP>
            </P>
        </Ps>
    </PP>
    <PP>
        <Ps>
            <StartMonth>5</StartMonth>
            <EndMonth>9</EndMonth>
            <P>
                <Amount>100</Amount>
                <startP>6</startP>
            </P>
            <P>
                <Amount>100</Amount>
                <startP>7</startP>
            </P>
            <P>
                <Amount>100</Amount>
                <startP>8</startP>
            </P>
            <P>
                <Amount>100</Amount>
                <startP>9</startP>
            </P>
            <P>
                <Amount>100</Amount>
                <startP>10</startP>
            </P>
        </Ps>
    </PP>
</PPS>

这是我的样本xslt

<xsl:stylesheet version="1.0" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
    <xsl:key name="x" match="Child" use="@Payment"/>
    <xsl:template match="/Root">
        <PPS>
            <xsl:for-each select="CF">
                <xsl:if test="generate-id(.) = generate-id(key('x',@Payment)[1])">
                    <PP>                        
                        <Ps>
                            <xsl:for-each select="key('x', @Payment)">
                                <P>
                                <Amount><xsl:value-of select="format-number(translate(@Payment, ',','.'),'0.00')"/></Amount>
                                <startP><xsl:value-of select="@Date"/></startP>
                                </P>
                            </xsl:for-each>
                        </Ps>
                    </PP>
                </xsl:if>
            </xsl:for-each>
        </PPS>
    </xsl:template>
</xsl:stylesheet>

1 个答案:

答案 0 :(得分:0)

这样可行:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/Root">
    <PPS>
        <xsl:for-each select="Child">
            <xsl:variable name="Payment" select="@Payment"/>
            <xsl:if test="not(preceding::*[1][self::Child and @Payment = $Payment])">
                <PPS>
                    <Ps>
                        <xsl:apply-templates select="current()"/>
                        <xsl:apply-templates select="following::*[1][self::Child and @Payment = $Payment]">
                            <xsl:with-param name="Payment" select="$Payment"/>
                        </xsl:apply-templates>
                    </Ps>
                </PPS>
            </xsl:if>
        </xsl:for-each>
    </PPS>
</xsl:template>
<xsl:template match="Child">
    <xsl:param name="Payment"/>
    <P>
        <Amount>
            <xsl:value-of select="@Payment"/>
        </Amount>
        <startP>
            <xsl:value-of select="@No"/>
        </startP>
    </P>
    <xsl:apply-templates select="following::*[1][self::Child and @Payment = $Payment]"/>
</xsl:template>
</xsl:stylesheet>