【问题标题】:How to Sum sub nodes in XSLT如何对 XSLT 中的子节点求和
【发布时间】:2021-08-15 04:39:25
【问题描述】:

我有传入 XSLT 的 xml 结构就像下面的代码。

<?xml version="1.0" encoding="UTF-8"?>
<TimeAccount>
    <TimeAccount>
        <userId>123</userId>
        <timeAccountDetails>
            <TimeAccountDetail>
                <bookingType>MANUAL_ADJUSTMENT</bookingType>
                <bookingUnit>HOURS</bookingUnit>
                <bookingDate>2021-01-01T00:00:00.000</bookingDate>
                <bookingAmount>190</bookingAmount>
            </TimeAccountDetail>
            <TimeAccountDetail>
                <employeeTime>e885f88ccaa647abb00a8f84bcf5aa32</employeeTime>
                <bookingType>EMPLOYEE_TIME</bookingType>
                <bookingUnit>HOURS</bookingUnit>
                <bookingDate>2021-04-19T00:00:00.000</bookingDate>
                <bookingAmount>-8</bookingAmount>
            </TimeAccountDetail>
            <TimeAccountDetail>
                <employeeTime>e885f88ccaa647abb00a8f84bcf5aa32</employeeTime>
                <bookingType>MANUAL_ADJUSTMENT</bookingType>
                <bookingUnit>HOURS</bookingUnit>
                <bookingDate>2021-04-20T00:00:00.000</bookingDate>
                <bookingAmount>120</bookingAmount>
            </TimeAccountDetail>
            <TimeAccountDetail>
                <employeeTime>e885f88ccaa647abb00a8f84bcf5aa32</employeeTime>
                <bookingType>EMPLOYEE_TIME</bookingType>
                <bookingUnit>HOURS</bookingUnit>
                <bookingDate>2021-04-21T00:00:00.000</bookingDate>
                <bookingAmount>-8</bookingAmount>
            </TimeAccountDetail>
        </timeAccountDetails>
    </TimeAccount>
        <TimeAccount>
        <userId>456</userId>
        <timeAccountDetails>
            <TimeAccountDetail>
                <bookingType>MANUAL_ADJUSTMENT</bookingType>
                <bookingUnit>HOURS</bookingUnit>
                <bookingDate>2021-01-01T00:00:00.000</bookingDate>
                <bookingAmount>190</bookingAmount>
            </TimeAccountDetail>
            <TimeAccountDetail>
                <employeeTime>e885f88ccaa647abb00a8f84bcf5aa32</employeeTime>
                <bookingType>EMPLOYEE_TIME</bookingType>
                <bookingUnit>HOURS</bookingUnit>
                <bookingDate>2021-04-19T00:00:00.000</bookingDate>
                <bookingAmount>-8</bookingAmount>
            </TimeAccountDetail>
            <TimeAccountDetail>
                <bookingType>MANUAL_ADJUSTMENT</bookingType>
                <bookingUnit>HOURS</bookingUnit>
                <bookingDate>2021-06-01T00:00:00.000</bookingDate>
                <bookingAmount>100</bookingAmount>
            </TimeAccountDetail>
            <TimeAccountDetail>
                <employeeTime>e885f88ccaa647abb00a8f84bcf5aa32</employeeTime>
                <bookingType>EMPLOYEE_TIME</bookingType>
                <bookingUnit>HOURS</bookingUnit>
                <bookingDate>2021-04-21T00:00:00.000</bookingDate>
                <bookingAmount>-8</bookingAmount>
            </TimeAccountDetail>
        </timeAccountDetails>
    </TimeAccount>
</TimeAccount>

我希望通过为每个 userId 添加 bookingAmount 来输出如下

<TimeAccount>
    <TimeAccount>
        <ID>123</ID>
        <bookingType>MANUAL_ADJUSTMENT</bookingType>
        <bookingAmount>310</bookingAmount>
    <TimeAccount>
        <TimeAccount>
        <ID>456</ID>
        <bookingType>MANUAL_ADJUSTMENT</bookingType>
        <bookingAmount>290</bookingAmount>
    <TimeAccount>
</TimeAccount>

我的 xslt 如下所示,使用 for-each 和 if 条件,然后使用 SUM 函数。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <TimeAccount>
            <xsl:apply-templates/>
        </TimeAccount>
    </xsl:template>
    <xsl:template match="TimeAccount/TimeAccount">
        <TimeAccount>
          <ID><xsl:value-of select="userId"/></ID>         
          <bookingAmount>
            <xsl:for-each select="timeAccountDetails/TimeAccountDetail">
                <xsl:if test="bookingType != 'EMPLOYEE_TIME'">
                   <xsl:value-of select="sum(bookingAmount)"/> 
                </xsl:if>
            </xsl:for-each>
            </TimeAccount>
    </xsl:template>
</xsl:stylesheet>

但输出不是添加 bookingAmounts 节点,而是并排打印节点。

<TimeAccount>
    <TimeAccount>
        <ID>123</ID>
        <bookingAmount>190 120</bookingAmount>
    <TimeAccount>
    <TimeAccount>
        <ID>456</ID>
        <bookingAmount>190 100</bookingAmount>
    <TimeAccount>
<TimeAccount>

我做错了什么?我尝试在预订金额之前保留 / ,例如 sum(/bookingAmount) 打印 null ,如果我输入 // 那么它会打印所有用户的 bookingAmounts 的总数。

【问题讨论】:

    标签: xml xslt xslt-1.0


    【解决方案1】:

    将您的 XSLT 代码更改为以下内容:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
        <xsl:template match="/TimeAccount">
            <xsl:copy>
                <xsl:apply-templates select="TimeAccount" />
            </xsl:copy>
        </xsl:template>
        
        <xsl:template match="TimeAccount">
          <xsl:copy>
            <ID><xsl:value-of select="userId"/></ID> 
            <bookingType>MANUAL_ADJUSTMENT</bookingType>        
            <bookingAmount><xsl:value-of select="sum(timeAccountDetails/TimeAccountDetail[bookingType != 'EMPLOYEE_TIME']/bookingAmount)"/></bookingAmount>
          </xsl:copy>
        </xsl:template>
        
    </xsl:stylesheet>
    

    输出应该和预期的一样:

    <?xml version="1.0"?>
    <TimeAccount>
        <TimeAccount>
            <ID>123</ID>
            <bookingType>MANUAL_ADJUSTMENT</bookingType>
            <bookingAmount>310</bookingAmount>
        </TimeAccount>
        <TimeAccount>
            <ID>456</ID>
            <bookingType>MANUAL_ADJUSTMENT</bookingType>
            <bookingAmount>290</bookingAmount>
        </TimeAccount>
    </TimeAccount>
    

    我将&lt;bookingType&gt; 固定为“MANUAL_ADJUSTMENT”,因为您只需要这些值(所有不是EMPLOYEE_TIME)。

    顺便说一句,您只需要 XSLT-1.0 即可完成此任务。 XSLT-3.0 功能只是一个奖励。

    【讨论】:

    • 这就像一个魔术,当与我的代码相比时, 做了所有的不同还是遍历节点?谢谢。
    【解决方案2】:

    这个 xslt 给出了预期的结果:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      
      <xsl:output indent="yes"/>
      
      <xsl:mode on-no-match="shallow-copy"/>
      
      <xsl:template match="userId">
        <ID>
          <xsl:value-of select="text()"/>
        </ID>
      </xsl:template>
      
      <xsl:template match="timeAccountDetails">
        <bookingType>MANUAL_ADJUSTMENT</bookingType>
        <bookingAmount>
          <xsl:value-of select="sum(TimeAccountDetail[bookingType='MANUAL_ADJUSTMENT']/bookingAmount)"/>
        </bookingAmount>
      </xsl:template>
      
    </xsl:stylesheet>
    

    当您使用 xslt 3.0 时,您可以使用

    <xsl:mode on-no-match="shallow-copy"/>
    

    等同于:

    <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
       </xsl:copy>
    </xsl:template>
    

    并且只会复制您没有模板匹配的任何内容。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-08
      相关资源
      最近更新 更多