Skip to content

Commit 1f45120

Browse files
committed
[bugfix] Fix issues with range, precision, and exponent with fn:xml-to-json
Closes #4304
1 parent 15b607d commit 1f45120

File tree

3 files changed

+77
-9
lines changed

3 files changed

+77
-9
lines changed

exist-core/src/main/java/org/exist/xquery/functions/fn/FunXmlToJson.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.io.IOException;
3535
import java.io.StringWriter;
3636
import java.io.Writer;
37+
import java.math.BigDecimal;
3738
import java.util.ArrayList;
3839

3940
import static org.exist.xquery.FunctionDSL.*;
@@ -179,7 +180,7 @@ private void nodeValueToJson(final NodeValue nodeValue, final Writer writer) thr
179180
break;
180181
case "number":
181182
try{
182-
final double tempDouble = Double.parseDouble(tempString);
183+
final BigDecimal tempDouble = new BigDecimal(tempString);
183184
jsonGenerator.writeNumber(tempDouble);
184185
} catch (NumberFormatException ex){
185186
throw new XPathException(ErrorCodes.FOJS0006, "Cannot convert '" + tempString + "' to a number.");

exist-core/src/main/java/org/exist/xquery/functions/fn/JSON.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,6 @@ public static void jsonToXml(MemTreeBuilder builder, JsonParser parser) throws I
358358
if(parser.getCurrentName() != null){
359359
builder.addAttribute(KEY, parser.getCurrentName());
360360
}
361-
// according to spec, all numbers are converted to double
362361
builder.characters(parser.getText());
363362
builder.endElement();
364363

exist-core/src/test/xquery/xquery3/xml-to-json.xql

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,15 @@ declare
5858
%test:arg('arg1', '')
5959
%test:assertError('FOJS0006')
6060
%test:arg('arg1', '0')
61-
%test:assertEquals('0.0')
61+
%test:assertEquals('0')
6262
%test:arg('arg1', '1')
63-
%test:assertEquals('1.0')
63+
%test:assertEquals('1')
6464
%test:arg('arg1', '-1')
65-
%test:assertEquals('-1.0')
65+
%test:assertEquals('-1')
6666
%test:arg('arg1', '01')
67-
%test:assertEquals('1.0') (: should error out for leading zeros according to spec :)
67+
%test:assertEquals('1')
6868
%test:arg('arg1', '08')
69-
%test:assertEquals('8.0') (: should error out for leading zeros according to spec :)
69+
%test:assertEquals('8')
7070
%test:arg('arg1', '3.1415')
7171
%test:assertEquals('3.1415')
7272
%test:arg('arg1', '0.31415e+1')
@@ -303,7 +303,7 @@ function xtj:xml-to-json-xmlInJsonString() {
303303
};
304304

305305
declare
306-
%test:assertEquals('{"pcM9qSs":"YbFYeK10.e01xgS1DEJFaxxvm372Ru","wh5J8qAmnZx8WAHnHCeBpM":-1.270212191431E9,"ssEhB3U9zZhRNNH2Vm":["A","OIQwg4ICB9fkzihwpE.cQv1",false]}')
306+
%test:assertEquals('{"pcM9qSs":"YbFYeK10.e01xgS1DEJFaxxvm372Ru","wh5J8qAmnZx8WAHnHCeBpM":-1270212191.431,"ssEhB3U9zZhRNNH2Vm":["A","OIQwg4ICB9fkzihwpE.cQv1",false]}')
307307
function xtj:xml-to-json-generatedFromSchema-1() {
308308
let $node :=
309309
<map xmlns="http://www.w3.org/2005/xpath-functions"
@@ -320,7 +320,7 @@ function xtj:xml-to-json-generatedFromSchema-1() {
320320
};
321321

322322
declare
323-
%test:assertEquals('{"v-DhbQUwZO3zpW":[{"fRcP.5e9btnuR3dOnd":[false,"_aQ",null],"yVlXSsyg1pPatQ7ilEaSSA9":"DVbrO2wpIRJimrskkRk.7wg1Gvh","K9xGofqp":true,"PatQ7iK9xGof":false},1.1145450201E7,5.84608693252E8],"IU6lSWbLYTzc3QvIVAdmJ.CG":1.600374222048E9,"_o3UT5zEy":"WFUwRRW5Jc3rdwKCoO8iV3RYDu_5"}')
323+
%test:assertEquals('{"v-DhbQUwZO3zpW":[{"fRcP.5e9btnuR3dOnd":[false,"_aQ",null],"yVlXSsyg1pPatQ7ilEaSSA9":"DVbrO2wpIRJimrskkRk.7wg1Gvh","K9xGofqp":true,"PatQ7iK9xGof":false},11145450.201,584608693.252],"IU6lSWbLYTzc3QvIVAdmJ.CG":1600374222.048,"_o3UT5zEy":"WFUwRRW5Jc3rdwKCoO8iV3RYDu_5"}')
324324
function xtj:xml-to-json-generatedFromSchema-2() {
325325
let $node :=
326326
<map xmlns="http://www.w3.org/2005/xpath-functions"
@@ -362,3 +362,71 @@ function xtj:xml-to-json-clearTextnodeBufferForNewElement() {
362362
let $node := <array><array> </array><string/></array>
363363
return fn:xml-to-json($node)
364364
};
365+
366+
declare
367+
%test:arg("int", "-1") %test:assertEquals('{"integer":-1}')
368+
%test:arg("int", "-1.0") %test:assertEquals('{"integer":-1.0}')
369+
%test:arg("int", "0") %test:assertEquals('{"integer":0}')
370+
%test:arg("int", "0.0") %test:assertEquals('{"integer":0.0}')
371+
%test:arg("int", "1") %test:assertEquals('{"integer":1}')
372+
%test:arg("int", "1.0") %test:assertEquals('{"integer":1.0}')
373+
function xtj:xmlmap-to-json-for-int-precision($int as xs:string) as xs:string {
374+
fn:xml-to-json(
375+
<map xmlns="http://www.w3.org/2005/xpath-functions">
376+
<number key="integer">{$int}</number>
377+
</map>
378+
)
379+
};
380+
381+
declare
382+
%test:arg("int", "-1") %test:assertXPath('$result/fn:map/fn:number = ''-1''')
383+
%test:arg("int", "-1.0") %test:assertXPath('$result/fn:map/fn:number = ''-1.0''')
384+
%test:arg("int", "0") %test:assertXPath('$result/fn:map/fn:number = ''0''')
385+
%test:arg("int", "0.0") %test:assertXPath('$result/fn:map/fn:number = ''0.0''')
386+
%test:arg("int", "1") %test:assertXPath('$result/fn:map/fn:number = ''1''')
387+
%test:arg("int", "1.0") %test:assertXPath('$result/fn:map/fn:number = ''1.0''')
388+
function xtj:json-to-xmlmap-for-int-precision($int as xs:string) as document-node() {
389+
fn:json-to-xml(
390+
'{"integer":' || $int || '}'
391+
)
392+
};
393+
394+
declare
395+
%test:arg("int", "1E9") %test:assertEquals('{"integer":1E+9}')
396+
%test:arg("int", "1E+9") %test:assertEquals('{"integer":1E+9}')
397+
%test:arg("int", "1E-9") %test:assertEquals('{"integer":1E-9}')
398+
%test:arg("int", "1e9") %test:assertEquals('{"integer":1E+9}')
399+
%test:arg("int", "1e+9") %test:assertEquals('{"integer":1E+9}')
400+
%test:arg("int", "1e-9") %test:assertEquals('{"integer":1E-9}')
401+
%test:arg("int", "1.1E9") %test:assertEquals('{"integer":1.1E+9}')
402+
%test:arg("int", "1.1E+9") %test:assertEquals('{"integer":1.1E+9}')
403+
%test:arg("int", "1.1E-9") %test:assertEquals('{"integer":1.1E-9}')
404+
%test:arg("int", "1.1e9") %test:assertEquals('{"integer":1.1E+9}')
405+
%test:arg("int", "1.1e+9") %test:assertEquals('{"integer":1.1E+9}')
406+
%test:arg("int", "1.1e-9") %test:assertEquals('{"integer":1.1E-9}')
407+
function xtj:xmlmap-to-json-for-exponent($int as xs:string) as xs:string {
408+
fn:xml-to-json(
409+
<map xmlns="http://www.w3.org/2005/xpath-functions">
410+
<number key="integer">{$int}</number>
411+
</map>
412+
)
413+
};
414+
415+
declare
416+
%test:arg("int", "1E9") %test:assertXPath('$result/fn:map/fn:number = ''1E9''')
417+
%test:arg("int", "1E+9") %test:assertXPath('$result/fn:map/fn:number = ''1E+9''')
418+
%test:arg("int", "1E-9") %test:assertXPath('$result/fn:map/fn:number = ''1E-9''')
419+
%test:arg("int", "1e9") %test:assertXPath('$result/fn:map/fn:number = ''1e9''')
420+
%test:arg("int", "1e+9") %test:assertXPath('$result/fn:map/fn:number = ''1e+9''')
421+
%test:arg("int", "1e-9") %test:assertXPath('$result/fn:map/fn:number = ''1e-9''')
422+
%test:arg("int", "1.1E9") %test:assertXPath('$result/fn:map/fn:number = ''1.1E9''')
423+
%test:arg("int", "1.1E+9") %test:assertXPath('$result/fn:map/fn:number = ''1.1E+9''')
424+
%test:arg("int", "1.1E-9") %test:assertXPath('$result/fn:map/fn:number = ''1.1E-9''')
425+
%test:arg("int", "1.1e9") %test:assertXPath('$result/fn:map/fn:number = ''1.1e9''')
426+
%test:arg("int", "1.1e+9") %test:assertXPath('$result/fn:map/fn:number = ''1.1e+9''')
427+
%test:arg("int", "1.1e-9") %test:assertXPath('$result/fn:map/fn:number = ''1.1e-9''')
428+
function xtj:json-to-xmlmap-for-exponent($int as xs:string) as document-node() {
429+
fn:json-to-xml(
430+
'{"integer":' || $int || '}'
431+
)
432+
};

0 commit comments

Comments
 (0)