Skip to content

Commit 65d3d5e

Browse files
authored
Merge pull request #4366 from evolvedbinary/feature/fn-format-integer#2,#3
Implement fn:format-integer#2,#3
2 parents 77bc41a + e3c5c8a commit 65d3d5e

File tree

13 files changed

+1908
-7
lines changed

13 files changed

+1908
-7
lines changed

exist-core/src/main/java/org/exist/test/runner/XMLTestRunner.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ public class XMLTestRunner extends AbstractTestRunner {
7979
/**
8080
* @param path The path to the XML file containing the tests.
8181
* @param parallel whether the tests should be run in parallel.
82-
*
8382
* @throws InitializationError if the test runner could not be constructed.
8483
*/
85-
public XMLTestRunner(final Path path, final boolean parallel) throws InitializationError {
84+
85+
XMLTestRunner(final Path path, final boolean parallel) throws InitializationError {
8686
super(path, parallel);
8787
try {
8888
this.doc = parse(path);
@@ -120,7 +120,7 @@ private static XMLTestInfo extractTestInfo(final Path path, final Document doc)
120120
testName = getTaskText(child);
121121
}
122122
if (testName == null) {
123-
throw new InitializationError("Could not find @id or <task> within <test> of XML <TestSet> document:" + path.toAbsolutePath().toString());
123+
throw new InitializationError("Could not find @id or <task> within <test> of XML <TestSet> document:" + path.toAbsolutePath());
124124
}
125125
testNames.add(testName);
126126
break;
@@ -133,7 +133,7 @@ private static XMLTestInfo extractTestInfo(final Path path, final Document doc)
133133
}
134134

135135
if (testSetName == null) {
136-
throw new InitializationError("Could not find <testName> in XML <TestSet> document: " + path.toAbsolutePath().toString());
136+
throw new InitializationError("Could not find <testName> in XML <TestSet> document: " + path.toAbsolutePath());
137137
}
138138

139139
return new XMLTestInfo(testSetName, description, testNames);
@@ -169,8 +169,7 @@ private static XMLTestInfo extractTestInfo(final Path path, final Document doc)
169169
}
170170

171171
private String getSuiteName() {
172-
final String suiteName = "xmlts." + info.getName(); // add "xmlts." prefix
173-
return suiteName;
172+
return "xmlts." + info.getName();
174173
}
175174

176175
@Override
@@ -213,7 +212,7 @@ public void run(final RunNotifier notifier) {
213212
}
214213
}
215214

216-
private Document parse(final Path path) throws ParserConfigurationException, IOException, SAXException {
215+
private static Document parse(final Path path) throws ParserConfigurationException, IOException, SAXException {
217216
final InputSource src = new InputSource(path.toUri().toASCIIString());
218217
final SAXParser parser = SAX_PARSER_FACTORY.newSAXParser();
219218
final XMLReader xr = parser.getXMLReader();
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* eXist-db Open Source Native XML Database
3+
* Copyright (C) 2001 The eXist-db Authors
4+
*
5+
6+
* http://www.exist-db.org
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; either
11+
* version 2.1 of the License, or (at your option) any later version.
12+
*
13+
* This library is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
* Lesser General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public
19+
* License along with this library; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
*/
22+
23+
package org.exist.xquery.functions.fn;
24+
25+
import org.exist.xquery.BasicFunction;
26+
import org.exist.xquery.FunctionSignature;
27+
import org.exist.xquery.XPathException;
28+
import org.exist.xquery.XQueryContext;
29+
import org.exist.xquery.functions.integer.IntegerPicture;
30+
import org.exist.xquery.value.*;
31+
32+
import java.math.BigInteger;
33+
import java.util.ArrayList;
34+
import java.util.List;
35+
36+
import static org.exist.xquery.FunctionDSL.*;
37+
import static org.exist.xquery.functions.fn.FnModule.functionSignatures;
38+
39+
/**
40+
* Implements fn:format-integer as per W3C XPath and XQuery Functions and Operators 3.1
41+
* <p>
42+
* fn:format-number($value as integer?, $picture as xs:string) as xs:string
43+
* fn:format-number($value as integer?, $picture as xs:string, $lang as xs:string) as xs:string
44+
*
45+
* @author <a href="mailto:[email protected]">Alan Paxton</a>
46+
*/
47+
public class FnFormatIntegers extends BasicFunction {
48+
49+
private static final FunctionParameterSequenceType FS_PARAM_VALUE = optParam("value", Type.NUMBER, "The number to format");
50+
private static final FunctionParameterSequenceType FS_PARAM_PICTURE = param("picture", Type.STRING, "The picture string to use for formatting. To understand the picture string syntax, see: https://www.w3.org/TR/xpath-functions-31/#func-format-number");
51+
52+
private static final String FS_FORMAT_INTEGER_NAME = "format-integer";
53+
static final FunctionSignature[] FS_FORMAT_INTEGER = functionSignatures(
54+
FS_FORMAT_INTEGER_NAME,
55+
"Returns a string containing an integer formatted according to a given picture string.",
56+
returns(Type.STRING, "The formatted string representation of the supplied integer"),
57+
arities(
58+
arity(
59+
FS_PARAM_VALUE,
60+
FS_PARAM_PICTURE
61+
),
62+
arity(
63+
FS_PARAM_VALUE,
64+
FS_PARAM_PICTURE,
65+
optParam("lang", Type.STRING, "The language in which to format the integers.")
66+
)
67+
)
68+
);
69+
70+
public FnFormatIntegers(final XQueryContext context, final FunctionSignature signature) {
71+
super(context, signature);
72+
}
73+
74+
@Override
75+
public Sequence eval(final Sequence[] args, final Sequence contextSequence)
76+
throws XPathException {
77+
// If $value is an empty sequence, the function returns a zero-length string
78+
// https://www.w3.org/TR/xpath-functions-31/#func-format-integer
79+
if (args[0].isEmpty()) {
80+
return Sequence.EMPTY_SEQUENCE;
81+
}
82+
83+
// If the value of $value is negative, the rules below are applied to the absolute value of $value,
84+
// and a minus sign is prepended to the result.
85+
final IntegerValue integerValue = (IntegerValue) args[0].itemAt(0);
86+
final BigInteger bigInteger = integerValue.toJavaObject(BigInteger.class);
87+
88+
final IntegerPicture picture = IntegerPicture.fromString(args[1].getStringValue());
89+
90+
// Build a list of languages to try
91+
// the called picture will use the first one with a valid locale
92+
final List<String> languages = new ArrayList<>(2);
93+
if (args.length == 3 && !args[2].isEmpty()) {
94+
languages.add(args[2].getStringValue());
95+
}
96+
languages.add(context.getDefaultLanguage());
97+
98+
return new StringValue(picture.formatInteger(bigInteger, languages));
99+
}
100+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ public class FnModule extends AbstractInternalModule {
9393
new FunctionDef(FnFormatDates.FNS_FORMAT_DATE_5, FnFormatDates.class),
9494
new FunctionDef(FnFormatDates.FNS_FORMAT_TIME_2, FnFormatDates.class),
9595
new FunctionDef(FnFormatDates.FNS_FORMAT_TIME_5, FnFormatDates.class),
96+
new FunctionDef(FnFormatIntegers.FS_FORMAT_INTEGER[0], FnFormatIntegers.class),
97+
new FunctionDef(FnFormatIntegers.FS_FORMAT_INTEGER[1], FnFormatIntegers.class),
9698
new FunctionDef(FnFormatNumbers.FS_FORMAT_NUMBER[0], FnFormatNumbers.class),
9799
new FunctionDef(FnFormatNumbers.FS_FORMAT_NUMBER[1], FnFormatNumbers.class),
98100
new FunctionDef(FunGenerateId.signatures[0], FunGenerateId.class),

0 commit comments

Comments
 (0)