#xquery #saxon #number-formatting
#xquery #saxon #форматирование чисел
Вопрос:
Я пытаюсь отформатировать десятичные дроби в 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 ()
)
};
Комментарии:
1. Хороший вопрос, 1. Смотрите мой ответ для полного и короткого решения 🙂
2. Не требуется использовать какой-либо префикс пространства имен для стандартных функций XPath. Если вы опустите
"fn:"
префикс, ваш код будет более читаемым. Кроме того, в настоящее время ваше кодирование непоследовательно: почему вы добавляете префикс кconcat()
функции, но не кsubstring()
function?3. @Dimitre: Обычно я не добавляю префиксы к стандартным функциям, но я скопировал эту функцию с веб-сайта, указанного выше. Это непоследовательно, потому что я не убрал префиксы, когда вносил изменения. Мне придется пройти через это и привести в порядок, чтобы это никого не смутило. Еще раз спасибо. Мы очень ценим вашу помощь!
Ответ №1:
Использовать:
let $n := 5573652.23
return
concat(local:format-int(xs:int(floor($n))),
'.',
substring(string($n - floor($n)), 3)
)
Это приводит именно к желаемому, правильному результату:
5,573,652.23
Комментарии:
1. Большое вам спасибо, Димитр. Основываясь на этом ответе, я обновил функцию, которую я использовал. 1 и ответ принят.
Ответ №2:
У вас это не работает?:
format-number(5573652.23,",###.##")
Вы можете поиграть с этим здесь. Я почти уверен, что saxon поддерживает эту функцию.
Редактировать: Эта функция не поддерживается в saxon (см. Комментарии ниже).
Комментарии:
1. Нет,
format-number()
не поддерживается. Это было первое, что я попробовал. Я попытался перейти с HE на PE amp; EE, но я все еще получаю сообщение об ошибке:F [Saxon-EE XQuery 9.3.0.4] System function format-number#2 is not available with this host language
. 1 за хорошее предложение, хотя2. Попробовал
fn:format-number($myelement/*:betrag cast as xs:decimal,"#,##0.00")
в XQuery 3.0 и с синтаксическим анализатором Saxon-HE 9.7, и это работает.
Ответ №3:
С помощью XQuery 3.0 и синтаксического анализатора Saxon-HE 9.7 вы можете сделать следующее:
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