You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于XSLT 1.0的XML双次转换:添加小计与统计元素

XSLT 1.0实现XML到XML的双阶段转换

我需要用XSLT 1.0完成XML到XML的转换,必须分至少两个阶段:

  • 第一阶段:为每个<item>计算subtotal(小计)
  • 第二阶段:基于这些小计生成包含totalPrice(总价)和totalQuantity(总数量)的<statistics>元素,并将其放在XML结构的顶部

输入XML

<?xml version="1.0" encoding="UTF-8"?>
<invoice>
    <orders>
        <order id="1">
            <lineitem id="1">
                <item quantity="2" price="100"/>
                <item quantity="3" price="50"/>
            </lineitem>
        </order>
        <order id="2">
            <lineitem id="1">
                <item quantity="5" price="20"/>
                <item quantity="1" price="100"/>
            </lineitem>
        </order>
    </orders>
</invoice>

期望输出XML

<?xml version="1.0" encoding="UTF-8"?>
<invoice>
    <statistics>
        <totalPrice>550</totalPrice>
        <totalQuantity>11</totalQuantity>
    </statistics>
    <orders>
        <order id="1">
            <lineitem id="1">
                <item quantity="2" price="100" subtotal="200"/>
                <item quantity="3" price="50" subtotal="150"/>
            </lineitem>
        </order>
        <order id="2">
            <lineitem id="1">
                <item quantity="5" price="20" subtotal="100"/>
                <item quantity="1" price="100" subtotal="100"/>
            </lineitem>
        </order>
    </orders>
</invoice>

问题与解决方案

我已经实现了为<item>添加subtotal的功能,但无法生成<statistics>元素。尝试将processedOrders设为全局变量未成功,最终通过**模式(mode)**实现双阶段转换完成需求,最终XSLT代码如下:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
                xmlns:exsl="http://exslt.org/common"
                extension-element-prefixes="exsl">

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

    <!-- 双阶段转换
    匹配/的模板是转换的入口点。
    通过将第一阶段的转换结果存入变量,再对该结果进行第二阶段处理,实现两次遍历输入。
    
    关键:使用模式区分仅在第二阶段执行的逻辑
    - 第一阶段(模板内第一次调用<xsl:apply-templates/>)无模式,会执行所有无模式的匹配模板
    - 第二阶段(第二次调用<xsl:apply-templates/>)使用"add-statistics"模式,会执行所有无模式模板以及匹配该模式的模板,确保统计元素仅在第二阶段添加,避免重复
    -->
    <xsl:template match="/">
        <xsl:variable name="first-transformation">
            <xsl:apply-templates/>
        </xsl:variable>
        <xsl:apply-templates select="exsl:node-set($first-transformation)/node()" mode="add-statistics"/>
    </xsl:template>

    <!-- 生成统计元素
    仅在调用模板的模式为"add-statistics"时生成包含总价和总数量的statistics元素。
    第一阶段无模式,会跳过该模板;第二阶段使用指定模式,因此会添加该元素,避免重复。
    -->
    <xsl:template match="invoice" mode="add-statistics">
        <invoice>
            <statistics>
                <totalPrice>
                    <xsl:value-of select="format-number(sum(//item/@subtotal),'0.00')"/>
                </totalPrice>
                <totalQuantity>
                    <xsl:value-of select="sum(//item/@quantity)"/>
                </totalQuantity>
            </statistics>
            <xsl:apply-templates/>
        </invoice>
    </xsl:template>

    <!-- 处理订单条目
    匹配item的模板会将每个item的price和quantity属性相乘计算小计,然后生成包含price、quantity和计算出的subtotal属性的新item元素。
    -->
    <xsl:template match="item">
        <xsl:variable name="subtotal" select="@price * @quantity"/>
        <item price="{@price}" quantity="{@quantity}" subtotal="{format-number($subtotal,'0.00')}"/>
    </xsl:template>

    <!-- 处理orders元素
    匹配orders的模板通过累加所有item的subtotal计算总价,然后生成带有totalPrice属性的新orders元素。
    -->
    <xsl:template match="orders">
        <orders totalPrice="{format-number(sum(//item/@subtotal),'0.00')}">
            <xsl:apply-templates/>
        </orders>
    </xsl:template>

    <!-- 标识模板
    这是XSLT中的常用设计模式,用于将源树转换为结果树时,仅修改部分内容,其余内容原样复制。
    该模板会复制所有未匹配到其他模板规则的节点和属性。
    -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

内容的提问来源于stack exchange,提问作者Robert Mark Bram

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 13:47:06