declare variable $decimalDecimalSeparator := "."; declare variable $decimalGroupSeparator := ","; declare variable $decimalZeroDigit := "0"; declare variable $decimalDigit := "#"; declare variable $decimalFormatPercent := "%"; declare variable $decimalGroupSeparatorCode := string-to-codepoints($decimalGroupSeparator)[1]; declare variable $decimalZeroDigitCode := string-to-codepoints($decimalZeroDigit)[1]; declare variable $decimalDigitCode := string-to-codepoints($decimalDigit)[1]; declare function local:format-number($inputNumber as xs:decimal, $inputFormat as xs:string) as xs:string { let $patterns := tokenize($inputFormat, ";") (: handle negative pattern :) let $format := if (count($patterns) = 1) then $inputFormat else if ($inputNumber > 0) then $patterns[1] else $patterns[2] (: if there is a pattern for negative numbers, let it handle the negative sign :) let $number1 as xs:decimal := if (count($patterns) = 1) then $inputNumber else if ($inputNumber > 0) then $inputNumber else -($inputNumber) (: if the pattern doesn't include a decimal separator, round the number :) let $number as xs:decimal := if(contains($format, $decimalDecimalSeparator)) then $number1 else round($number1) let $strNumber := string( if (ends-with($format, $decimalFormatPercent)) then $number*100 else $number ) let $decimalPart := codepoints-to-string( local:format-number-decimal( string-to-codepoints( substring-after($strNumber, '.') ), string-to-codepoints( substring-after($format, $decimalDecimalSeparator) ) ) ) let $integerPart := codepoints-to-string( local:format-number-integer( reverse( string-to-codepoints( if(starts-with($strNumber, "0.")) then "" else if( contains($strNumber, '.') ) then substring-before($strNumber, '.') else $strNumber ) ), reverse( string-to-codepoints( if( contains($format, $decimalDecimalSeparator) ) then substring-before($format, $decimalDecimalSeparator) else $format ) ), 0, -1 ) ) return if (string-length($decimalPart) > 0) then concat($integerPart, $decimalDecimalSeparator, $decimalPart) else $integerPart }; declare function local:format-number-decimal($number as xs:integer*, $format as xs:integer*) as xs:integer* { if ($format[1] = $decimalDigitCode or $format[1] = $decimalZeroDigitCode) then if (count($number) > 0) then ($number[1], local:format-number-decimal(subsequence($number, 2), subsequence($format, 2))) else if ($format[1] = $decimalDigitCode) then () else ($format[1], local:format-number-decimal((), subsequence($format, 2))) else if (count($format) > 0) then ($format[1], local:format-number-decimal($number, subsequence($format, 2))) else () }; declare function local:format-number-integer($number as xs:integer*, $format as xs:integer*, $thousandsCur as xs:integer, $thousandsPos as xs:integer) as xs:integer* { if( $thousandsPos > 0 and $thousandsPos = $thousandsCur and count($number) > 0) then (local:format-number-integer($number, $format, 0, $thousandsCur), $decimalGroupSeparatorCode) else if ($format[1] = $decimalDigitCode or $format[1] = $decimalZeroDigitCode) then if (count($number) > 0) then (local:format-number-integer(subsequence($number, 2), subsequence($format, 2), $thousandsCur+1, $thousandsPos), $number[1]) else if ($format[1] = $decimalDigitCode) then (local:format-number-integer((), subsequence($format, 2), $thousandsCur+1, $thousandsPos)) else (local:format-number-integer((), subsequence($format, 2), $thousandsCur+1, $thousandsPos), $format[1]) else if (count($format) > 0) then if ($format[1] = $decimalGroupSeparatorCode) then if (count($number) = 0 and $format[2] != $decimalZeroDigitCode) then (local:format-number-integer($number, subsequence($format, 2), 0, $thousandsCur)) else (local:format-number-integer($number, subsequence($format, 2), 0, $thousandsCur), $format[1]) else (: some other character :) if (count($number) > 0) then (: digits come first of any other character in $format :) (local:format-number-integer(subsequence($number, 2), $format, $thousandsCur+1, $thousandsPos), $number[1]) else (local:format-number-integer($number, subsequence($format, 2), $thousandsCur+1, $thousandsPos), $format[1]) else if (count($number) > 0) then (local:format-number-integer(subsequence($number, 2), $format, $thousandsCur+1, $thousandsPos), $number[1]) else () }; local:format-number(12345678.9, '#,###.00') {local:format-number(12345678.9, '#,###.00')} 12,345,678.90 local:format-number(-12345678.9, '#,###.00') {local:format-number(-12345678.9, '#,###.00')} -12,345,678.90 local:format-number(12345.67,'00000000.00') {local:format-number(12345.67,'00000000.00')} 00012345.67 local:format-number(12345.67,'0,000.0000;-000,000.00') {local:format-number(12345.67,'0,000.0000;-000,000.00')} 12,345.6700 local:format-number(-12345.67,'0,000.0000;-000,000.00') {local:format-number(-12345.67,'0,000.0000;-000,000.00')} -012,345.67 local:format-number(12345.67,',000') {local:format-number(12345.67,',000')} 12,346 local:format-number(12345.67,'$,000') {local:format-number(12345.67,'$,000')} $12,346