Skip to content

Commit 5086400

Browse files
authored
Merge pull request eXist-db#4435 from evolvedbinary/feature/fn-collation-key#1,#2
Implement the fn:collation-key XQuery function
2 parents 95e4b61 + b563513 commit 5086400

File tree

6 files changed

+283
-15
lines changed

6 files changed

+283
-15
lines changed

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
@@ -52,6 +52,8 @@ public class FnModule extends AbstractInternalModule {
5252
new FunctionDef(FunCeiling.signature, FunCeiling.class),
5353
new FunctionDef(FunCodepointEqual.signature, FunCodepointEqual.class),
5454
new FunctionDef(FunCodepointsToString.signature, FunCodepointsToString.class),
55+
new FunctionDef(FunCollationKey.FS_COLLATION_KEY_SIGNATURES[0], FunCollationKey.class),
56+
new FunctionDef(FunCollationKey.FS_COLLATION_KEY_SIGNATURES[1], FunCollationKey.class),
5557
new FunctionDef(FunCompare.signatures[0], FunCompare.class),
5658
new FunctionDef(FunCompare.signatures[1], FunCompare.class),
5759
new FunctionDef(FunConcat.signature, FunConcat.class),
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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.apache.commons.codec.binary.Base64;
26+
import org.exist.util.Collations;
27+
import org.exist.xquery.*;
28+
import org.exist.xquery.value.*;
29+
30+
import com.ibm.icu.text.Collator;
31+
32+
import java.io.IOException;
33+
import java.nio.charset.StandardCharsets;
34+
35+
import static org.exist.xquery.FunctionDSL.*;
36+
import static org.exist.xquery.functions.fn.FnModule.functionSignatures;
37+
38+
public class FunCollationKey extends BasicFunction {
39+
40+
private static final String FN_NAME = "collation-key";
41+
private static final String FN_DESCRIPTION =
42+
"Given a $value-string value and a $collation-string " +
43+
"collation, generates an internal value called a collation key, with the " +
44+
"property that the matching and ordering of collation " +
45+
"keys reflects the matching and ordering of strings " +
46+
"under the specified collation.";
47+
private static final FunctionReturnSequenceType FN_RETURN = returnsOpt(Type.BASE64_BINARY, "the collation key");
48+
private static final FunctionParameterSequenceType PARAM_VALUE_STRING = param("value-string", Type.STRING, "The value string");
49+
private static final FunctionParameterSequenceType PARAM_COLLATION_STRING = param("collation-string", Type.STRING, "The collation string");
50+
public static final FunctionSignature[] FS_COLLATION_KEY_SIGNATURES = functionSignatures(
51+
FN_NAME,
52+
FN_DESCRIPTION,
53+
FN_RETURN,
54+
arities(
55+
arity(PARAM_VALUE_STRING),
56+
arity(PARAM_VALUE_STRING, PARAM_COLLATION_STRING)
57+
)
58+
);
59+
60+
public FunCollationKey(final XQueryContext context, final FunctionSignature signature) {
61+
super(context, signature);
62+
}
63+
64+
public Sequence eval(final Sequence[] args, final Sequence contextSequence) throws XPathException {
65+
final String source = (args.length >= 1) ? args[0].itemAt(0).toString() : "";
66+
final Collator collator = (args.length >= 2) ? Collations.getCollationFromURI(args[1].itemAt(0).toString()) : null;
67+
final Sequence sequence;
68+
try (BinaryValueFromBinaryString binaryValue = new BinaryValueFromBinaryString(
69+
new Base64BinaryValueType(),
70+
Base64.encodeBase64String(
71+
(collator == null) ?
72+
source.getBytes(StandardCharsets.UTF_8) :
73+
new String(collator.getCollationKey(source).toByteArray()).getBytes(StandardCharsets.UTF_8)))) {
74+
sequence = binaryValue.convertTo(new Base64BinaryValueType());
75+
} catch (IOException e) {
76+
return null;
77+
}
78+
return sequence;
79+
}
80+
}

exist-core/src/main/java/org/exist/xquery/value/BinaryValue.java

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,13 @@ private int compareTo(BinaryValue otherValue) {
109109
return -1;
110110
} else if (otherIs == null) {
111111
return 1;
112+
} else if (is == otherIs) {
113+
return 0;
112114
} else {
113-
int read = -1;
114-
int otherRead = -1;
115-
while (true) {
115+
int read;
116+
int otherRead;
117+
do {
118+
116119
try {
117120
read = is.read();
118121
} catch (final IOException ioe) {
@@ -125,8 +128,12 @@ private int compareTo(BinaryValue otherValue) {
125128
return 1;
126129
}
127130

128-
return read - otherRead;
129-
}
131+
final int readComparison = Integer.compare(read, otherRead);
132+
if (readComparison != 0) {
133+
return readComparison;
134+
}
135+
} while (read != -1 && otherRead != -1);
136+
return 0;
130137
}
131138
}
132139

@@ -276,4 +283,33 @@ public void streamTo(OutputStream os) throws IOException {
276283
* Increments the number of shared references to this binary value.
277284
*/
278285
public abstract void incrementSharedReferences();
286+
287+
@Override
288+
public boolean equals(Object o) {
289+
if (this == o) return true;
290+
if (o == null || getClass() != o.getClass()) return false;
291+
BinaryValue that = (BinaryValue) o;
292+
return compareTo(that) == 0;
293+
}
294+
295+
@Override
296+
public int hashCode() {
297+
final InputStream is = getInputStream();
298+
int hash = 7;
299+
300+
if (is != null) {
301+
int read;
302+
do {
303+
try {
304+
read = is.read();
305+
if (read != -1) {
306+
hash = 31 * hash + read;
307+
}
308+
} catch (final IOException ioe) {
309+
read = -1;
310+
}
311+
} while (read != -1);
312+
}
313+
return hash;
314+
}
279315
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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+
xquery version "3.1";
23+
24+
module namespace fnp="http://exist-db.org/xquery/test/function_codepoint_equal";
25+
26+
declare namespace test="http://exist-db.org/xquery/xqsuite";
27+
28+
declare
29+
%test:assertEmpty
30+
function fnp:empty-sequences() {
31+
fn:codepoint-equal((), ())
32+
};
33+
34+
declare
35+
%test:assertEmpty
36+
function fnp:empty-string-and-empty-sequence() {
37+
fn:codepoint-equal("", ())
38+
};
39+
40+
declare
41+
%test:assertTrue
42+
function fnp:empty-strings() {
43+
fn:codepoint-equal("", "")
44+
};
45+
46+
declare
47+
%test:assertTrue
48+
function fnp:equal() {
49+
fn:codepoint-equal("abcd", "abcd")
50+
};
51+
52+
declare
53+
%test:assertFalse
54+
function fnp:not-equal() {
55+
fn:codepoint-equal("abcd", "abcd ")
56+
};
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
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+
xquery version "3.1";
23+
24+
module namespace fnck="http://exist-db.org/xquery/test/function_collation_key";
25+
26+
declare namespace test="http://exist-db.org/xquery/xqsuite";
27+
28+
declare
29+
%test:assertTrue
30+
function fnck:default-equal() {
31+
let $first := fn:collation-key("a")
32+
let $second := fn:collation-key("a")
33+
return $first eq $second
34+
};
35+
36+
declare
37+
%test:assertTrue
38+
function fnck:default-not-equal() {
39+
let $first := fn:collation-key("a")
40+
let $second := fn:collation-key("b")
41+
return $first ne $second
42+
};
43+
44+
declare
45+
%test:assertTrue
46+
function fnck:default-not-equal-ignore-case() {
47+
let $first := fn:collation-key("a")
48+
let $second := fn:collation-key("A")
49+
return $first ne $second
50+
};
51+
52+
declare
53+
%test:assertTrue
54+
function fnck:exist-equal() {
55+
let $first := fn:collation-key("a", "http://exist-db.org/collation")
56+
let $second := fn:collation-key("a", "http://exist-db.org/collation")
57+
return $first eq $second
58+
};
59+
60+
declare
61+
%test:assertTrue
62+
function fnck:exist-not-equal() {
63+
let $first := fn:collation-key("a", "http://exist-db.org/collation")
64+
let $second := fn:collation-key("b", "http://exist-db.org/collation")
65+
return $first ne $second
66+
};
67+
68+
declare
69+
%test:assertTrue
70+
function fnck:exist-not-equal-ignore-case() {
71+
let $first := fn:collation-key("a", "http://exist-db.org/collation")
72+
let $second := fn:collation-key("A", "http://exist-db.org/collation")
73+
return $first ne $second
74+
};
75+
76+
declare
77+
%test:assertError("FOCH0002")
78+
function fnck:invalid-uri() {
79+
fn:collation-key("a", "")
80+
};
81+
82+
declare
83+
%test:assertTrue
84+
function fnck:uca-equal() {
85+
let $first := fn:collation-key("a", "http://www.w3.org/2013/collation/UCA?lang=en;strength=primary")
86+
let $second := fn:collation-key("a", "http://www.w3.org/2013/collation/UCA?lang=en;strength=primary")
87+
return $first eq $second
88+
};
89+
90+
declare
91+
%test:assertTrue
92+
function fnck:uca-equal-ignore-case() {
93+
let $first := fn:collation-key("a", "http://www.w3.org/2013/collation/UCA?lang=en;strength=primary")
94+
let $second := fn:collation-key("A", "http://www.w3.org/2013/collation/UCA?lang=en;strength=primary")
95+
return $first eq $second
96+
};
97+
98+
declare
99+
%test:assertTrue
100+
function fnck:uca-not-equal() {
101+
let $first := fn:collation-key(fn:codepoints-to-string((37, 65500, 37)))
102+
let $second := fn:collation-key(fn:codepoints-to-string((37, 100000, 37)))
103+
return $first lt $second
104+
};

extensions/modules/compression/src/test/xquery/modules/compression/zip-tests.xql

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,6 @@ declare variable $z:myStaticUTF8ContentBase64 := xs:base64Binary("UEsDBBQACAgIAO
4141

4242

4343

44-
declare
45-
%test:user("guest", "guest")
46-
%test:assertTrue
47-
function z:fnZipUtf8Content() {
48-
let $z:myZipEntries := (<entry name="{$z:myFile-name}" type="xml">{$z:myFile-serialized}</entry>),
49-
$z:myZipContentUTF8Base64 := compression:zip($z:myZipEntries, true(), "", "UTF8")
50-
return
51-
($z:myZipContentUTF8Base64 eq $z:myStaticUTF8ContentBase64)
52-
};
53-
5444
(: Verify zero byte sized resource :)
5545
declare
5646
%test:assertEquals("")

0 commit comments

Comments
 (0)