Как я могу отформатировать десятичное число в xquery?

Я пытаюсь отформатировать десятичные дроби в 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 в качестве процессора.

Любая помощь будет принята с благодарностью.

----- ОБНОВЛЕНИЕ -----

Основываясь на ответе Дмитрия, я изменил функцию, чтобы сохранить десятичную часть и добавить ее в конец возвращаемой строки.

Новая функция

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 ()
                )
};

person Daniel Haley    schedule 30.04.2011    source источник
comment
Хороший вопрос, +1. Смотрите мой ответ для полного и краткого решения :)   -  person Dimitre Novatchev    schedule 01.05.2011
comment
Для стандартных функций XPath не требуется использовать какой-либо префикс пространства имен. Если вы опустите префикс "fn:", ваш код будет более читабельным. Кроме того, в настоящее время ваше кодирование непоследовательно: почему вы ставите префикс функции concat(), а не функции substring()?   -  person Dimitre Novatchev    schedule 02.05.2011
comment
@Dimitre: я обычно не добавляю префикс к стандартным функциям, но я скопировал эту функцию с указанного выше веб-сайта. Это непоследовательно, потому что я не удалил префиксы, когда вносил изменения. Я должен пройти и очистить его, чтобы он никого не смущал. Еще раз спасибо. Ваша помощь очень ценится!   -  person Daniel Haley    schedule 02.05.2011


Ответы (3)


Использование:

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

Это приводит к желаемому правильному результату:

5,573,652.23
person Dimitre Novatchev    schedule 01.05.2011
comment
Большое спасибо Димитри. Основываясь на этом ответе, я обновил функцию, которую использовал. +1 и ответ принят. - person Daniel Haley; 02.05.2011

Это не работает для вас?:

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

Вы можете поиграть с этим здесь. Я почти уверен, что saxon поддерживает эту функцию.

Изменить: эта функция не поддерживается на саксонском языке (см. комментарии ниже).

person Dennis Münkle    schedule 30.04.2011
comment
Нет, 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 за хорошее предложение, хотя - person Daniel Haley; 01.05.2011
comment
Пробовал fn:format-number($myelement/*:betrag cast as xs:decimal,"#,##0.00") в XQuery 3.0 и с парсером Saxon-HE 9.7, все работает. - person the hand of NOD; 05.03.2019

С помощью 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
person the hand of NOD    schedule 06.03.2019