如何在没有属性的情况下对 XML 进行分组

how to group XML without attributes

我的任务是修改前段时间离开公司的其他人制作的工具。最后要做的是按日期对 XML 进行分组。我发现的每个示例都使用 XML 和属性,所以它并不是很有帮助。

我的XML没有单一属性,它的结构是这样的:

<report>
<clientInfo>
...
</clientInfo>
<bills>
    <bill>
        <section>
            <dateSegment>20-07-1990</dateSegment>
            <money>100</money>
            <days>9</days>
        </section>
        <section>
            <dateSegment>20-08-1990</dateSegment>
            <money>130</money>
            <days>4</days>
        </section>
        <section>
            <dateSegment>20-09-1990</dateSegment>
            <money>110</money>
            <days>5</days>
        </section>
    </bill>
    <bill>
        <section>
            <dateSegment>20-07-1990</dateSegment>
            <money>230</money>
            <days>11</days>
        </section>
        <section>
            <dateSegment>20-10-1990</dateSegment>
            <money>210</money>
            <days>3</days>
        </section>
    </bill>
    ...
</bills>
...
</report>

我必须按同一日期分组,然后对每组进行总结。我尝试根据 how to apply group by on xslt elements post 编写模板,但它远未按预期工作。

<xsl:key name="by_date" match="section" use="@dateSegment" />

<xsl:template name="test">
    <xsl:element name="AllSections">
        <xsl:for-each-group select="*" group-by="@dateSegment">
            <xsl:element name="dateSegment">
                <xsl:attribute name="value">
                    <xsl:value-of select="@dateSegment" />
                </xsl:attribute>
                <xsl:for-each select="current-group()">
                    <xsl:element name="section">
                        <xsl:element name="money"><xsl:value-of select="@money" /></xsl:element>
                        <xsl:element name="days"><xsl:value-of select="@days" /></xsl:element>
                    </xsl:element>
                </xsl:for-each>
              </xsl:element>
       </xsl:for-each-group>
    </xsl:element>
</xsl:template>

尝试用 <xsl:call-template name="test"/> 调用它但没有任何反应,结果为空。

预期输出:

任一

<dateSegment value="20-07-1990">
    <section>
        <money>100</money>
        <days>9</days>
    </section>
    <section>
        <money>230</money>
        <days>11</days>
    </section>
</dateSegment>
<dateSegment value="20-08-1990">
    <section>
        <money>130</money>
        <days>4</days>
    </section>
</dateSegment>
...

<dateSegment>
    <money>340</money>
    <days>11</days> (max value from <days> in same section)
</dateSegment>
<dateSegment>   
    <money>130</money>
    <days>4</days>
    </section>
</dateSegment>

将 XML 分配给变量会很有帮助,这样我就可以用它做一些事情。

Alrdy 问了我能问的每个人,但是我们 none 的人都在处理这样的事情,但没有人能够帮助我。

知道怎么做吗?

首先,您提到没有属性,但XSLT 仍在使用属性语法;即 @dateSegment。引用元素应该是dateSegment

您似乎还想对 section 元素进行分组,而不管它们位于哪个 bill 元素中(而不是在每个 bill 元素中进行单独分组)。但是您当前的 XSLT 正在执行 <xsl:for-each-group select="*" 如果您在 bill 元素上,这实际上只会给您结果。确实,您想定位在 bills 元素上,然后执行此操作:

<xsl:for-each-group select="bill/section" group-by="dateSegment">

试试这个 XSLT(我已经简化以删除 xsl:elementxsl:attribute 的使用)

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

<xsl:output method="xml" indent="yes" />

<xsl:template match="bills">
    <AllSections>
        <xsl:for-each-group select="bill/section" group-by="dateSegment">
            <dateSegment value="{dateSegment}">
                <xsl:for-each select="current-group()">
                    <section>
                        <money><xsl:value-of select="money" /></money>
                        <days><xsl:value-of select="days" /></days>
                    </section>
                </xsl:for-each>
            </dateSegment>
        </xsl:for-each-group>
    </AllSections>
</xsl:template>

</xsl:stylesheet>

如果您想汇总结果,请执行此操作

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

<xsl:output method="xml" indent="yes" />

<xsl:template match="bills">
    <AllSections>
        <xsl:for-each-group select="bill/section" group-by="dateSegment">
            <dateSegment value="{dateSegment}">
                <money><xsl:value-of select="sum(current-group()/money)" /></money>
                <days><xsl:value-of select="max(current-group()/days)" /></days>
            </dateSegment>
        </xsl:for-each-group>
    </AllSections>
</xsl:template>

</xsl:stylesheet>