Skip to content

Commit 1f3d901

Browse files
committed
[feature] Implement 'declare default decimal-format' and 'declare decimal-format' prolog options in XQuery
1 parent e0e0fc8 commit 1f3d901

File tree

5 files changed

+200
-3
lines changed

5 files changed

+200
-3
lines changed

exist-core/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,7 @@
11031103
<include>src/test/java/org/exist/xquery/CleanupTest.java</include>
11041104
<include>src/test/java/org/exist/xquery/ConstructedNodesRecoveryTest.java</include>
11051105
<include>src/main/java/org/exist/xquery/Context.java</include>
1106+
<include>src/main/java/org/exist/xquery/DecimalFormat.java</include>
11061107
<include>src/main/java/org/exist/xquery/DeferredFunctionCall.java</include>
11071108
<include>src/main/java/org/exist/xquery/DynamicCardinalityCheck.java</include>
11081109
<include>src/main/java/org/exist/xquery/DynamicTypeCheck.java</include>
@@ -1285,6 +1286,7 @@
12851286
<include>src/main/java/org/exist/xquery/functions/xmldb/XMLDBStore.java</include>
12861287
<include>src/main/java/org/exist/xquery/functions/xmldb/XMLDBXUpdate.java</include>
12871288
<include>src/test/java/org/exist/xquery/functions/xquery3/TryCatchTest.java</include>
1289+
<include>src/main/antlr/org/exist/xquery/parser/XQuery.g</include>
12881290
<include>src/main/antlr/org/exist/xquery/parser/XQueryTree.g</include>
12891291
<include>src/test/java/org/exist/xquery/update/AbstractUpdateTest.java</include>
12901292
<include>src/test/java/org/exist/xquery/update/IndexIntegrationTest.java</include>
@@ -1783,6 +1785,7 @@
17831785
<exclude>src/test/java/org/exist/xquery/CleanupTest.java</exclude>
17841786
<exclude>src/test/java/org/exist/xquery/ConstructedNodesRecoveryTest.java</exclude>
17851787
<exclude>src/main/java/org/exist/xquery/Context.java</exclude>
1788+
<exclude>src/main/java/org/exist/xquery/DecimalFormat.java</exclude>
17861789
<exclude>src/main/java/org/exist/xquery/DeferredFunctionCall.java</exclude>
17871790
<exclude>src/main/java/org/exist/xquery/DynamicCardinalityCheck.java</exclude>
17881791
<exclude>src/main/java/org/exist/xquery/DynamicTypeCheck.java</exclude>
@@ -1991,6 +1994,7 @@
19911994
<exclude>src/main/java/org/exist/xquery/functions/xmldb/XMLDBXUpdate.java</exclude>
19921995
<exclude>src/test/java/org/exist/xquery/functions/xquery3/SerializeTest.java</exclude>
19931996
<exclude>src/test/java/org/exist/xquery/functions/xquery3/TryCatchTest.java</exclude>
1997+
<exclude>src/main/antlr/org/exist/xquery/parser/XQuery.g</exclude>
19941998
<exclude>src/main/antlr/org/exist/xquery/parser/XQueryTree.g</exclude>
19951999
<exclude>src/main/java/org/exist/xquery/pragmas/TimePragma.java</exclude>
19962000
<exclude>src/test/java/org/exist/xquery/update/AbstractUpdateTest.java</exclude>

exist-core/src/main/antlr/org/exist/xquery/parser/XQuery.g

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
/*
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
4+
*
5+
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; version 2.1.
11+
*
12+
* This library is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this library; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*
21+
* NOTE: Parts of this file contain code from 'The eXist-db Authors'.
22+
* The original license header is included below.
23+
*
24+
* =====================================================================
25+
*
226
* eXist-db Open Source Native XML Database
327
* Copyright (C) 2001 The eXist-db Authors
428
*
@@ -150,6 +174,8 @@ imaginaryTokenDefinitions
150174
NAMESPACE_DECL
151175
DEF_NAMESPACE_DECL
152176
DEF_COLLATION_DECL
177+
DECIMAL_FORMAT_DECL
178+
DEFAULT_DECIMAL_FORMAT
153179
DEF_FUNCTION_NS_DECL
154180
CONTEXT_ITEM_DECL
155181
ANNOT_DECL
@@ -256,7 +282,7 @@ prolog throws XPathException
256282
(
257283
importDecl
258284
|
259-
( "declare" ( "default" | "boundary-space" | "ordering" | "construction" | "base-uri" | "copy-namespaces" | "namespace" ) ) =>
285+
( "declare" ( "default" | "boundary-space" | "ordering" | "construction" | "base-uri" | "copy-namespaces" | "namespace" | "decimal-format" ) ) =>
260286
s:setter
261287
{
262288
if(!inSetters)
@@ -295,10 +321,44 @@ versionDecl throws XPathException
295321
{ #versionDecl = #(#[VERSION_DECL, v.getText()], enc); }
296322
;
297323
324+
dfPropertyName
325+
:
326+
"decimal-separator"
327+
| "grouping-separator"
328+
| "infinity"
329+
| "minus-sign"
330+
| "NaN"
331+
| "percent"
332+
| "per-mille"
333+
| "zero-digit"
334+
| "digit"
335+
| "pattern-separator"
336+
| "exponent-separator"
337+
;
338+
339+
decimalFormatDecl
340+
{ String dfName = null; }
341+
:
342+
"declare"!
343+
(
344+
"default" "decimal-format"
345+
( dfPropertyName EQ! STRING_LITERAL )*
346+
{
347+
## = #( #[DECIMAL_FORMAT_DECL, "DECIMAL_FORMAT_DECL"], #[DEFAULT_DECIMAL_FORMAT, "DEFAULT_DECIMAL_FORMAT"], ## );
348+
}
349+
|
350+
"decimal-format" eqName
351+
( dfPropertyName EQ! STRING_LITERAL )*
352+
{
353+
## = #( #[DECIMAL_FORMAT_DECL, "DECIMAL_FORMAT_DECL"], ## );
354+
}
355+
)
356+
;
357+
298358
setter
299359
:
300360
(
301-
( "declare" "default" ) =>
361+
( "declare" "default" ( "collation" | "element" | "function" | "order" ) ) =>
302362
"declare"! "default"!
303363
(
304364
"collation"! defc:STRING_LITERAL
@@ -330,6 +390,8 @@ setter
330390
|
331391
( "declare" "namespace" ) =>
332392
namespaceDecl
393+
| ( "declare" ( "default" )? "decimal-format" ) =>
394+
decimalFormatDecl
333395
)
334396
;
335397

exist-core/src/main/antlr/org/exist/xquery/parser/XQueryTree.g

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,56 @@ throws PermissionDeniedException, EXistException, XPathException
511511
}
512512
)
513513
|
514+
#(
515+
DECIMAL_FORMAT_DECL
516+
{
517+
final XQueryAST root = (XQueryAST) _t; // points to DECIMAL_FORMAT_DECL
518+
// first sibling is either DEFAULT_DECIMAL_FORMAT (default) or EQNAME (named)
519+
final XQueryAST dfName = (XQueryAST) root.getNextSibling();
520+
521+
// position current at the first property name for the decimal format
522+
XQueryAST current = (XQueryAST) dfName.getNextSibling();
523+
if ("default".equals(dfName.getText())) {
524+
current = (XQueryAST) current.getNextSibling();
525+
}
526+
527+
final Map<String, String> dfProperties = new HashMap<>();
528+
529+
while (current != null) {
530+
final XQueryAST pname = current;
531+
final XQueryAST pval = (XQueryAST) current.getNextSibling();
532+
533+
if (pval == null) {
534+
break;
535+
}
536+
537+
final String pn = pname.getText();
538+
String pv = pval.getText();
539+
if (pv.length() >= 2 && (pv.startsWith("\"") || pv.startsWith("'"))) {
540+
pv = pv.substring(1, pv.length() - 1);
541+
}
542+
dfProperties.put(pn, pv);
543+
544+
current = (XQueryAST) pval.getNextSibling();
545+
}
546+
547+
final QName qnDfName;
548+
if ("default".equals(dfName.getText())) {
549+
qnDfName = XQueryContext.UNNAMED_DECIMAL_FORMAT;
550+
} else {
551+
try {
552+
qnDfName = QName.parse(staticContext, dfName.getText(), null);
553+
} catch (final IllegalQNameException iqe) {
554+
throw new XPathException(dfName.getLine(), dfName.getColumn(), ErrorCodes.XPST0081, "No namespace defined for prefix " + dfName.getText());
555+
}
556+
}
557+
558+
final DecimalFormat df = DecimalFormat.fromProperties(dfProperties);
559+
staticContext.setStaticDecimalFormat(qnDfName, df);
560+
context.setStaticDecimalFormat(qnDfName, df);
561+
}
562+
)
563+
|
514564
#(
515565
qname:GLOBAL_VAR
516566
{

exist-core/src/main/java/org/exist/xquery/DecimalFormat.java

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
/*
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
4+
*
5+
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; version 2.1.
11+
*
12+
* This library is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this library; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*
21+
* NOTE: Parts of this file contain code from 'The eXist-db Authors'.
22+
* The original license header is included below.
23+
*
24+
* =====================================================================
25+
*
226
* eXist-db Open Source Native XML Database
327
* Copyright (C) 2001 The eXist-db Authors
428
*
@@ -21,6 +45,8 @@
2145
*/
2246
package org.exist.xquery;
2347

48+
import java.util.Map;
49+
2450
/**
2551
* Data class for a Decimal Format.
2652
*
@@ -79,4 +105,59 @@ public DecimalFormat(final int decimalSeparator, final int exponentSeparator, fi
79105
this.NaN = NaN;
80106
this.minusSign = minusSign;
81107
}
108+
109+
public static DecimalFormat fromProperties(final Map<String, String> properties) {
110+
int decimalSeparator = UNNAMED.decimalSeparator;
111+
int exponentSeparator = UNNAMED.exponentSeparator;
112+
int groupingSeparator = UNNAMED.groupingSeparator;
113+
int percent = UNNAMED.percent;
114+
int perMille = UNNAMED.perMille;
115+
int zeroDigit = UNNAMED.zeroDigit;
116+
int digit = UNNAMED.digit;
117+
int patternSeparator = UNNAMED.patternSeparator;
118+
String infinity = UNNAMED.infinity;
119+
String NaN = UNNAMED.NaN;
120+
int minusSign = UNNAMED.minusSign;
121+
122+
for (final Map.Entry<String, String> property : properties.entrySet()) {
123+
final String value = property.getValue();
124+
switch (property.getKey()) {
125+
case "decimal-separator":
126+
decimalSeparator = value.charAt(0);
127+
break;
128+
case "exponent-separator":
129+
exponentSeparator = value.charAt(0);
130+
break;
131+
case "grouping-separator":
132+
groupingSeparator = value.charAt(0);
133+
break;
134+
case "percent":
135+
percent = value.charAt(0);
136+
break;
137+
case "per-mille":
138+
perMille = value.charAt(0);
139+
break;
140+
case "zero-digit":
141+
zeroDigit = value.charAt(0);
142+
break;
143+
case "digit":
144+
digit = value.charAt(0);
145+
break;
146+
case "pattern-separator":
147+
patternSeparator = value.charAt(0);
148+
break;
149+
case "infinity":
150+
infinity = value;
151+
break;
152+
case "NaN":
153+
NaN = value;
154+
break;
155+
case "minus-sign":
156+
minusSign = value.charAt(0);
157+
break;
158+
}
159+
}
160+
161+
return new DecimalFormat(decimalSeparator, exponentSeparator, groupingSeparator, percent, perMille, zeroDigit, digit, patternSeparator, infinity, NaN, minusSign);
162+
}
82163
}

exist-core/src/main/java/org/exist/xquery/XQueryContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ public class XQueryContext implements BinaryValueManager, Context {
443443
*/
444444
@Nullable
445445
private HttpContext httpContext = null;
446-
private static final QName UNNAMED_DECIMAL_FORMAT = new QName("__UNNAMED__", Namespaces.XPATH_FUNCTIONS_NS);
446+
public static final QName UNNAMED_DECIMAL_FORMAT = new QName("__UNNAMED__", Namespaces.XPATH_FUNCTIONS_NS);
447447

448448
private final Map<QName, DecimalFormat> staticDecimalFormats = hashMap(Tuple(UNNAMED_DECIMAL_FORMAT, DecimalFormat.UNNAMED));
449449

0 commit comments

Comments
 (0)