XSLT:基于其他属性名称,计算特定属性值的总和

5

我有以下XML文档(由另一方提供)

<transactions>
  <transaction TaxAType="11" TaxAValue="111" TaxBType="2" TaxBValue="222" TaxCType="3" TaxCValue="333"/>
  <transaction TaxAType="11" TaxAValue="111" TaxBType="2" TaxBValue="222" TaxCType="3" TaxCValue="333"/>
</transactions>

我希望写一个XSLT文档,如果对应的Tax*Type='11',则转换这些行并汇总Tax*Value。

如果不使用模板,是否有可能实现这个功能?

XQuery中的name()、substring()等函数能否实现?您对此有什么想法?


结果应该是什么样子的?只有一个数字吗?还是一些包含总数的XML?你说“例如Tax*Type ='11'”。这是否意味着在您的示例XML中,TaxBValue和TaxCValue不会被求和? - JLRishe
好的,我的想法是将某种类型的10个值的总和存储在我转换后的文档的属性中。例如:<batch gstAmount=5433"> transformed-transactions-elements </batch> - Daniel St-Jean
这并没有很清楚地阐明问题。这次“10”类型是从哪里来的?你是如何得出5433这个结果的?你能详细描述一下你想做什么吗?鉴于你在问题中提供的示例XML,输出应该是什么? - JLRishe
所以,如果GST等于税类型11,则gstAmount将为222。问题在于,税类型11可能存储在TaxAType和/或TaxBType和/或TaxCType中。 - Daniel St-Jean
我明白了。谢谢你的澄清。如果你有兴趣,我在下面发布了一个通用解决方案。 - JLRishe
4个回答

14

请看下面的XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="/">

    Sum of TaxA where type = 11:
    <xsl:value-of select="sum(transactions/transaction[@TaxAType='11']/@TaxAValue)" />

    Sum of all tax where type = 11:
    <xsl:value-of select="sum(transactions/transaction[@TaxAType='11']/@TaxAValue) 
      + sum(transactions/transaction[@TaxBType='11']/@TaxBValue) 
      + sum(transactions/transaction[@TaxCType='11']/@TaxCValue)" />

  </xsl:template>
</xsl:stylesheet>

它计算TaxAType为11的节点的TaxAValue之和以及TaxType为11的所有节点的Tax?Value之和。


这个可行!谢谢...我一开始想用更通用的方法,使用一个用户定义函数,但由于模式是预定义的,所以这可以工作! 谢谢! - Daniel St-Jean

1
这里是一种有些冗长但通用的方法:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:param name="taxType" select="11" />

  <xsl:template match="transactions">
    <result>
      <xsl:variable name="allValues" 
                    select="transaction/@*[substring(local-name(), 5, 5) = 'Type']
                                          [. = $taxType]" />
      <xsl:call-template name="SumValues">
        <xsl:with-param name="items" select="$allValues" />
      </xsl:call-template>
    </result>
  </xsl:template>

  <xsl:template name="SumValues">
    <xsl:param name="items" />
    <xsl:param name="total" select="0" />

    <xsl:choose>
      <xsl:when test="not($items)">
        <xsl:value-of select="$total" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="currentItem" select="$items[1]" />
        <xsl:variable name="currentValue">
          <xsl:apply-templates select="$currentItem" mode="getMatchingValue" />
        </xsl:variable>

        <xsl:call-template name="SumValues">
          <xsl:with-param name="items" select="$items[position() > 1]" />
          <xsl:with-param name="total" select="$total +  $currentValue" />
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="@*" mode="getMatchingValue">
    <xsl:variable name="typeCodeLetter" select="substring(local-name(), 4, 1)" />
    <xsl:variable name="valueAttributeName"
                  select="concat('Tax', $typeCodeLetter, 'Value')" />
    <xsl:variable name="matchingValueAttribute"
                  select="../@*[local-name() = $valueAttributeName]" />

    <!-- Multiply by boolean to handle the case where the 
         attribute wasn't found-->
    <xsl:value-of select="$matchingValueAttribute * 
                          boolean($matchingValueAttribute)"/>
  </xsl:template>
</xsl:stylesheet>

这应该能够处理任意数量的 Tax*Type(只要 * 是单个字符),并且所需类型可以作为参数传递。

0

这个XML格式不适合于完成您所要求的处理类型。您最好使用具有XML功能的JavaScript或其他语言(如C#,Java等)来提取所需的详细信息。

使用JavaScript,您可以查找任何属性中的Tax * Type = 11,然后获取下一个属性的值。


我相信这不是纯XSL,但我可能已经找到了一个合理的方法,创建一个用户定义函数,该函数将接收所有名称为Tax?Type且值为11的属性的节点列表,然后UDF将查找并汇总“对应项”即Tax?Value。 - Daniel St-Jean

0

sum(transactions/transaction[@TaxAType='11']/@TaxAValue | @TaxBvalue | @ TaxCvalue)

总和(transactions/transaction[@TaxAType='11']/@TaxAValue | @TaxBvalue | @ TaxCvalue)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接