如何在 xquery 中格式化小数?

Posted

技术标签:

【中文标题】如何在 xquery 中格式化小数?【英文标题】:How can I format a decimal in xquery? 【发布时间】:2011-08-15 20:44:34 【问题描述】:

我正在尝试在 XQuery 中格式化小数。小数点是货币,所以格式应该是,###.##

例如:

5573652.23 应该是5,573,652.23

352769 应该是 352,769(或者 352,769.00,如果它更容易/更干净)

现在我正在使用http://www.xqueryhacker.com/2009/09/format-number-in-xquery/ 的这个函数,但我不能使用小数:

declare function local:format-int($i as xs:int) as xs:string

  let $input :=
    if ($i lt 0) then fn:substring(fn:string($i), 2)
    else fn:string($i)
  let $rev := fn:reverse(fn:string-to-codepoints(fn:string($input)))
  let $comma := fn:string-to-codepoints(',')

  let $chars :=
    for $c at $i in $rev
    return (
      $c,
      if ($i mod 3 eq 0 and fn:not($i eq count($rev)))
      then $comma else ()
    )

  return fn:concat(
    if ($i lt 0) then '-' else (),
    fn:codepoints-to-string(fn:reverse($chars))
  )
;

我的处理器使用 Saxon 9HE。

任何帮助将不胜感激。

----- 更新 -----

根据 Dimitre 的回答,我修改了函数以保存小数部分并将其添加到返回字符串的末尾。

新功能

declare function local:format-dec($i as xs:decimal) as xs:string

  let $input := tokenize(string(abs($i)),'\.')[1]
  let $dec := substring(tokenize(string($i),'\.')[2],1,2)
  let $rev := reverse(string-to-codepoints(string($input)))
  let $comma := string-to-codepoints(',')

  let $chars :=
    for $c at $i in $rev
    return (
      $c,
      if ($i mod 3 eq 0 and not($i eq count($rev)))
      then $comma else ()
    )

  return concat(if ($i lt 0) then '-' else (),
                codepoints-to-string(reverse($chars)),
                if ($dec != '') then concat('.',$dec) else ()
                )
;

【问题讨论】:

好问题,+1。请参阅我的答案以获得完整而简短的解决方案:) 标准 XPath 函数不需要使用任何命名空间前缀。如果您省略 "fn:" 前缀,您的代码将更具可读性。另外,目前你的编码不​​一致:为什么你在concat()函数前加上前缀,而不是substring()函数前缀? @Dimitre:我通常不会为标准函数添加前缀,但我从上面提到的网站复制了这个函数。这是不一致的,因为我在进行修改时没有去掉前缀。我必须通过并清理它,以免混淆任何人。再次感谢。非常感谢您的帮助! 【参考方案1】:

使用 XQuery 3.0 和 Saxon-HE 9.7 Parser,您可以执行以下操作:

declare decimal-format local:de decimal-separator = "," grouping-separator = ".";
declare decimal-format local:en decimal-separator = "." grouping-separator = ",";
let $numbers := (1234.567, 789, 1234567.765)
for $i in $numbers
return (
   format-number($i,"#.###,##","local:de"),
   format-number($i,"#,###.##","local:en")
)

输出是:

<?xml version="1.0" encoding="UTF-8"?>1.234,57 1,234.57 789,0 789.0 1.234.567,76 
1,234,567.76

【讨论】:

【参考方案2】:

这对你不起作用?:

format-number(5573652.23,",###.##")

你可以玩这个here。我很确定撒克逊人支持这个功能。

编辑:saxon 不支持此功能(请参阅下面的 cmets)。

【讨论】:

不,不支持format-number()。那是我尝试的第一件事。我尝试从 HE 更改为 PE & EE,但仍然出现错误:F [Saxon-EE XQuery 9.3.0.4] System function format-number#2 is not available with this host language。 +1 为一个很好的建议虽然 XQuery 3.0 和 Saxon-HE 9.7 Parser 中尝试了 fn:format-number($myelement/*:betrag cast as xs:decimal,"#,##0.00"),它可以工作。【参考方案3】:

使用

let $n := 5573652.23
 return
      concat(local:format-int(xs:int(floor($n))),
             '.',
             substring(string($n - floor($n)), 3)
             )

这会产生所需的正确结果

5,573,652.23

【讨论】:

非常感谢 Dimitre。基于这个答案,我更新了我正在使用的功能。 +1 并接受回答。

以上是关于如何在 xquery 中格式化小数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 xquery 赋值中使用 if else

在xquery中如何进行换行

如何在 XQuery 中选择节点的属性值?

如何对字符串中的 XML 运行 XQuery?

如何使用 XQuery 获取 XML 文件中的子节点数

在启动我想要运行的完整 XQuery 之前,如何验证嵌入在较大 XQuery 中的 Lucene 查询不包含语法错误?