XPath格式 - 基于变量的小数位数?

时间:2010-01-07 16:09:21

标签: xml xslt xpath xslt-2.0

我有一个XML文档,其中应报告特定xs:decimal的小数位数保存在同级节点中。我目前正在努力寻找一种通过format-number函数输出的简单方法。

我可以用一些其他函数构建一个图片字符串,但这似乎非常冗长,应该(至少是imo)一个相对简单和常见的任务。

e.g。我目前正在做的是这样的事情:

<xsl:value-of
 select="format-number(myNode/DecimalValue,
         concat('#0.', 
                string-join(for $i in 1 to myNode/DecimalPlaces return '0'))"
/>

有更好的方法吗?

2 个答案:

答案 0 :(得分:4)

非常好的问题!这通常意味着,我不知道答案,但我希望其他人这样做,因为这对我来说也是一种痛苦。

无论如何,我做了一些搜索,我认为round-half-to-even函数可以解决问题(http://www.xqueryfunctions.com/xq/fn_round-half-to-even.html

您的代码将变为:

<xsl:value-of 
  select="
    round-half-to-even(
      myNode/DecimalValue
    , myNode/DecimalPlaces
    )
  "
/>

现在关闭一点切线: 对于使用XSLT 1.1或更低版本以及XPath 1的用户,可以使用:

<xsl:value-of 
  select="
    concat(
      substring-before(DecimalValue, '.')
    , '.'
    , substring(substring-after(DecimalValue, '.'), 1, DecimalPlaces -1)
    , round(
        concat(
          substring(substring-after(DecimalValue, '.'), DecimalPlaces, 1)
        ,   '.'
        ,   substring(substring-after(DecimalValue, '.'), DecimalPlaces+1)
        )
      )
    )
  "
/>

当然,这段代码更糟比原版更好,但是如果有人知道如何解决XPath 1的原始问题并且有比这更好的想法,我很乐意听到。 (越来越多的时候,我希望世界完全跳过XML并立即转向JSON)

答案 1 :(得分:2)

<!-- use a generous amount of zeros in a top-level variable -->
<xsl:variable name="zeros" select="'000000000000000000000000000000000'" />

<!-- …time passes… -->
<xsl:value-of select="
  format-number(
     myNode/DecimalValue,
     concat('#0.', substring($zeros, 1, myNode/DecimalPlaces))
  )
" />

您可以将其抽象为模板:

<!-- template mode is merely to prevent collisions with other templates -->
<xsl:template match="myNode" mode="FormatValue">
  <xsl:value-of select="
    format-number(
      DecimalValue, 
      concat('#0.', substring($zeros, 1, DecimalPlaces))
    )
  " />
</xsl:template>

<!-- call like this -->
<xsl:apply-templates select="myNode" mode="FormatValue" />

您还可以创建一个命名模板,并在调用它时使用XSLT上下文节点。如果这对您来说可取决于您的输入文档和需求。

<xsl:template name="FormatValue">
  <!-- same as above -->
</xsl:template>

<!-- call like this -->
<xsl:for-each select="myNode">
  <xsl:call-template name="FormatValue" />
</xsl:for-each>