XSLT:我们可以使用绝对值吗?

4

我想知道在XLST中是否可以使用math:abs(...)? 我在某处看到过,但它不起作用。 我有类似于:

<tag>
  <xsl:value-of select="./product/blablaPath"/>
</tag>

我尝试做了以下操作:

<tag>
  <xsl:value-of select="math:abs(./product/blablaPath)"/>
</tag>

但是无法工作。我使用的是Java 1.6语言。


1
dup?https://dev59.com/1nRA5IYBdhLWcg3w2xsI - Rubens Farias
我刚刚添加了一个一行代码的解决方案 :) - Dimitre Novatchev
5个回答

7

这里有一个单一的XPath表达式实现了abs()函数:

($x >= 0)*$x - not($x >= 0)*$x

这将被评估为 abs($x)

以下是此过程的简要演示:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

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

 <xsl:template match="text()">
  <xsl:param name="x" select="."/>
  <xsl:value-of select=
  "($x >= 0)*$x - not($x >= 0)*$x"/>
 </xsl:template>
</xsl:stylesheet>

当这种转换应用于以下XML文档时:
<t>
  <num>-3</num>
  <num>0</num>
  <num>5</num>
</t>

想要的、正确的结果(对每个数字使用abs())已经生成

<t>
  <num>3</num>
  <num>0</num>
  <num>5</num>
</t>

1
@tomalak 实际上,这只是 abs() 函数的定义。如果 $x >= 0,则为 $x(乘以1), 如果 $x < 0,则为 $x 乘以 -1上述条件是互斥的,因此恰好有一个条件为真(1),另一个条件为假(0)。我们使用这个方法来求和这两个条件,并生成一个单一的公式。 - Dimitre Novatchev
@Dimitre:这就是所谓的“Becker's Method”,当应用于字符串时。 :) 请参阅Олэг的博客:http://www.tkachenko.com/blog/archives/000156.html。 - Tomalak
@tomalak 这是XPath 1.0将布尔转换为数字的一个属性。它已被广泛使用,不仅被 O.B. 使用。 - Dimitre Novatchev
这个对我好像没有起作用,也许你可以展示一下它被使用的例子。 - James
@James:我已经在我的答案中添加了完整的XSLT转换和一个XML文档,你可以将其复制/粘贴到你喜欢的XSLT IDE中,然后运行转换。如果你的代码仍然有问题,那么可能是你的代码中还有其他问题。请在xslt标签中提出问题,并通过评论通知我。 - Dimitre Novatchev
抱歉打扰一下,但我也在尝试实现这个功能,但它没有起作用。由于我必须这样做,我无法从节点中创建变量:{((entry/transaction-total >= 0)*entry/transaction-total - not(entry/transaction-total >= 0)*entry/transaction-total) -sum(((entry/transaction-splits/item/amount >= 0)*entry/transaction-splits/item/amount - not(entry/transaction-splits/item/amount >= 0)*entry/transaction-splits/item/amount))} - designermonkey

3

abs() 很简单。如果用纯 XSLT 实现,它会像这样:

<xsl:template name="abs">
  <xsl:param name="number">

  <xsl:choose>
    <xsl:when test="$number &gt;= 0">
      <xsl:value-of select="$number" />
    <xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$number * -1" />
    </xsl:otherwise>
  </xsl:if>
</xsl:template>

在你的上下文中,你可以这样调用它:
<tag>
  <xsl:call-template name="abs">
    <xsl:with-param name="number" select="number(product/blablaPath)" />
  </xsl:call-template>
</tag>

实际上,我找到了解决方案。 已经有一个math:abs实现。 我只是使用了 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:math="xalan://java.lang.Math" extension-element-prefixes="math">对于我的节点, 我放置了"math:abs(...)" - CC.
我的解决方案针对 XSLT 1.0,因为你没有提到可以使用版本2.0。 - Tomalak
1
我刚刚添加了一个一行代码的解决方案 :) - Dimitre Novatchev

3

一种非常简单的解决方案是使用XSL 1.0的translate函数。

<xsl:value-of select="translate($x, '-', '')/>

1
另一种方式:

(2*($x >= 0) - 1)*$x

当$x$为正数时,测试返回“true”,因此$2\times true-1$返回1,因此最终结果为$x$。 当$x$为负数时,测试返回“false”,因此$2\times false-1$返回-1,因此最终结果为-$x$。

Using

2*(any-test-here)-1
is a good way to have +1 when test is true, and -1 when false.


0

math:abs 在 XSLT 或 XPATH 中不是内置的。它是一种 XSLT 扩展,由您正在转换的运行时提供。

这里有一篇关于 .NET xslt extensions 的文章。

这里还有一个 Java(Xalan)的扩展。


我更倾向于仅修改XSLT文件而不是Java代码,因为Java代码会有很大的影响。 - CC.
很遗憾。math:abs 将由您的 Java 代码作为 XSLT 扩展提供。阅读链接的文章以了解如何将其暴露给您的 XSLT。 - Oded

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