在 XSLT 中实现 product()

Posted

技术标签:

【中文标题】在 XSLT 中实现 product()【英文标题】:Implementing product() in XSLT 【发布时间】:2014-10-27 00:33:27 【问题描述】:

XPath 2.0(和 3.0)具有方便的聚合函数 sum() 和 avg(),但没有返回数值原子值序列的乘积。

虽然在允许赋值语句的语言中实现这样的函数是微不足道的,但在 XSLT 中似乎并不那么容易。我发现获得聚合产品的唯一方法是使用递归:

<xsl:function name="fn:products">
  <xsl:param name="input" />
  <xsl:param name="total" />
  <xsl:if test="exists($input)">
    <xsl:variable name="x" select="$input[1] * $total"/>
    <xsl:sequence select="$x"/>
    <xsl:sequence select="fn:products(subsequence($input,2),$x)"/>
  </xsl:if>
</xsl:function>

但以上实际上是我对 Michael Kay 的书 XSLT 2.0 和 XPath 2.0 4th Edition 的 p.994 中出现的一个函数的改编。原始函数通过递归添加一个数字序列来输出一个运行余额序列。

我的版本只是将数字相乘,而不是相加。结果是一系列“运行产品”。例如,fn:products((4, 0.75, 10, 0.7), 1) 返回序列 4, 3, 30, 21。

由于我只对所有数字的乘积感兴趣,因此我只使用过滤器表达式获取输出的最后一项:fn:products((4, 0.75, 10, 0.7), 1)[last() ]。

它有效。但是只是为了编写好的代码,我想知道是否有一种方法可以使函数直接将最后一项作为聚合产品返回(即在上面的示例中只得到 21)。

我尝试了几件事,但他们只是破坏了功能。有没有办法做到这一点?是否也可以以更好、更精简的方式实现它(原始函数并不是要返回单例序列)?

【问题讨论】:

【参考方案1】:

如果您使用其中一种高级处理器,您可以使用 dyn:evaluate。

<?xml version="1.0" encoding="UTF-8"?>
<test>
    <num>4</num>
    <num>0.75</num>
    <num>10</num>
    <num>0.7</num>
</test>

<?xml version="1.0" encoding="UTF-8"?>

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

    <xsl:template match="/">
        <xsl:variable name="run">
            <xsl:for-each select="test/num"><xsl:value-of select="."/><xsl:if test="position() != last()"> * </xsl:if></xsl:for-each>
        </xsl:variable>

        <xsl:value-of select="dyn:evaluate(string($run))"/>

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

【讨论】:

将在运行时构造为字符串的 XPath 表达式求值。是的。这是一个非常好的解决方案。我没有想到。与 altova:evaluate() 配合得很好,也应该与 saxon:evaluate() 配合得很好。谢谢,更快。

以上是关于在 XSLT 中实现 product()的主要内容,如果未能解决你的问题,请参考以下文章

XPath 2.0 和/或 XSLT 2.0 会在 PHP 中实现吗?

如何使用 XSLT 从 XML 中删除货币符号?

如何在 xpath 表达式中实现具有名称的用户定义函数?

我将如何在 SSIS 数据流中实现此查询?

左连接连接中的 LIKE 语句

如何实现 XSLT 标记化功能?