Skip to content

Commit c9e2b4d

Browse files
committed
[bugfix] New implementation of the fn:doc-available#1 XPath function
Closes eXist-db/exist#5220
1 parent 790e1e0 commit c9e2b4d

File tree

4 files changed

+136
-91
lines changed

4 files changed

+136
-91
lines changed

exist-core/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,7 @@
993993
<include>src/main/java/org/exist/xquery/functions/fn/FnHasChildren.java</include>
994994
<include>src/main/java/org/exist/xquery/functions/fn/FnInnerMost.java</include>
995995
<include>src/main/java/org/exist/xquery/functions/fn/FnTransform.java</include>
996+
<include>src/main/java/org/exist/xquery/functions/fn/FunDocAvailable.java</include>
996997
<include>src/test/java/org/exist/xquery/functions/fn/FunXmlToJsonTest.java</include>
997998
<include>src/test/java/org/exist/xquery/functions/fn/ParsingFunctionsTest.java</include>
998999
<include>src/main/java/org/exist/xquery/functions/fn/transform/Convert.java</include>
@@ -1275,6 +1276,8 @@
12751276
<include>src/main/java/org/exist/xquery/UserDefinedFunction.java</include>
12761277
<include>src/main/java/org/exist/xquery/XQueryContext.java</include>
12771278
<include>src/test/java/org/exist/xquery/XQueryFunctionsTest.java</include>
1279+
<include>src/test/java/org/exist/xquery/functions/fn/DocTest.java</include>
1280+
<include>src/main/java/org/exist/xquery/functions/fn/FnModule.java</include>
12781281
<include>src/main/java/org/exist/xquery/functions/fn/FunBaseURI.java</include>
12791282
<include>src/main/java/org/exist/xquery/functions/fn/FunDeepEqual.java</include>
12801283
<include>src/main/java/org/exist/xquery/functions/fn/FunParseIetfDate.java</include>
@@ -1703,14 +1706,17 @@
17031706
<exclude>src/test/java/org/exist/xquery/XQueryContextAttributesTest.java</exclude>
17041707
<exclude>src/test/java/org/exist/xquery/XQueryFunctionsTest.java</exclude>
17051708
<exclude>src/test/java/org/exist/xquery/XQueryIsLibraryModuleTest.java</exclude>
1709+
<exclude>src/test/java/org/exist/xquery/functions/fn/DocTest.java</exclude>
17061710
<exclude>src/main/java/org/exist/xquery/functions/fn/FnDefaultLanguage.java</exclude>
17071711
<exclude>src/main/java/org/exist/xquery/functions/fn/FnFormatIntegers.java</exclude>
17081712
<exclude>src/main/java/org/exist/xquery/functions/fn/FnFormatNumbers.java</exclude>
17091713
<exclude>src/main/java/org/exist/xquery/functions/fn/FnHasChildren.java</exclude>
17101714
<exclude>src/main/java/org/exist/xquery/functions/fn/FnInnerMost.java</exclude>
1715+
<exclude>src/main/java/org/exist/xquery/functions/fn/FnModule.java</exclude>
17111716
<exclude>src/main/java/org/exist/xquery/functions/fn/FnTransform.java</exclude>
17121717
<exclude>src/main/java/org/exist/xquery/functions/fn/FunBaseURI.java</exclude>
17131718
<exclude>src/main/java/org/exist/xquery/functions/fn/FunDeepEqual.java</exclude>
1719+
<exclude>src/main/java/org/exist/xquery/functions/fn/FunDocAvailable.java</exclude>
17141720
<exclude>src/main/java/org/exist/xquery/functions/fn/FunParseIetfDate.java</exclude>
17151721
<exclude>src/main/java/org/exist/xquery/functions/fn/FunTrace.java</exclude>
17161722
<exclude>src/main/java/org/exist/xquery/functions/fn/FunUriCollection.java</exclude>

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

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,31 @@
11
/*
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
4+
*
5+
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
7+
*
8+
* Use of this software is governed by the Business Source License 1.1
9+
* included in the LICENSE file and at www.mariadb.com/bsl11.
10+
*
11+
* Change Date: 2028-04-27
12+
*
13+
* On the date above, in accordance with the Business Source License, use
14+
* of this software will be governed by the Apache License, Version 2.0.
15+
*
16+
* Additional Use Grant: Production use of the Licensed Work for a permitted
17+
* purpose. A Permitted Purpose is any purpose other than a Competing Use.
18+
* A Competing Use means making the Software available to others in a commercial
19+
* product or service that: substitutes for the Software; substitutes for any
20+
* other product or service we offer using the Software that exists as of the
21+
* date we make the Software available; or offers the same or substantially
22+
* similar functionality as the Software.
23+
*
24+
* NOTE: Parts of this file contain code from 'The eXist-db Authors'.
25+
* The original license header is included below.
26+
*
27+
* =====================================================================
28+
*
229
* eXist-db Open Source Native XML Database
330
* Copyright (C) 2001 The eXist-db Authors
431
*
@@ -33,6 +60,7 @@
3360
/**
3461
* Module function definitions for xpath-functions module.
3562
*
63+
* @author <a href="mailto:[email protected]">Adam Retter</a>
3664
* @author <a href="mailto:[email protected]">Wolfgang Meier</a>
3765
* @author ljo
3866
*/
@@ -73,7 +101,7 @@ public class FnModule extends AbstractInternalModule {
73101
new FunctionDef(FunDistinctValues.signatures[0], FunDistinctValues.class),
74102
new FunctionDef(FunDistinctValues.signatures[1], FunDistinctValues.class),
75103
new FunctionDef(FunDoc.signature, FunDoc.class),
76-
new FunctionDef(FunDocAvailable.signature, FunDocAvailable.class),
104+
new FunctionDef(FunDocAvailable.FS_DOC_AVAILABLE, FunDocAvailable.class),
77105
new FunctionDef(FunDocumentURI.FS_DOCUMENT_URI_0, FunDocumentURI.class),
78106
new FunctionDef(FunDocumentURI.FS_DOCUMENT_URI_1, FunDocumentURI.class),
79107
new FunctionDef(FunElementWithId.FS_ELEMENT_WITH_ID_SIGNATURES[0], FunElementWithId.class),
Lines changed: 54 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,87 @@
11
/*
2-
* eXist-db Open Source Native XML Database
3-
* Copyright (C) 2001 The eXist-db Authors
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
44
*
5-
6-
* http://www.exist-db.org
5+
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
77
*
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.
8+
* Use of this software is governed by the Business Source License 1.1
9+
* included in the LICENSE file and at www.mariadb.com/bsl11.
1210
*
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.
11+
* Change Date: 2028-04-27
1712
*
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
13+
* On the date above, in accordance with the Business Source License, use
14+
* of this software will be governed by the Apache License, Version 2.0.
15+
*
16+
* Additional Use Grant: Production use of the Licensed Work for a permitted
17+
* purpose. A Permitted Purpose is any purpose other than a Competing Use.
18+
* A Competing Use means making the Software available to others in a commercial
19+
* product or service that: substitutes for the Software; substitutes for any
20+
* other product or service we offer using the Software that exists as of the
21+
* date we make the Software available; or offers the same or substantially
22+
* similar functionality as the Software.
2123
*/
2224
package org.exist.xquery.functions.fn;
2325

24-
import org.apache.logging.log4j.LogManager;
25-
import org.apache.logging.log4j.Logger;
26-
27-
import org.exist.dom.QName;
28-
import org.exist.xquery.*;
29-
import org.exist.xquery.functions.xmldb.XMLDBModule;
26+
import org.exist.xquery.BasicFunction;
27+
import org.exist.xquery.ErrorCodes;
28+
import org.exist.xquery.FunctionSignature;
29+
import org.exist.xquery.XPathException;
30+
import org.exist.xquery.XQueryContext;
3031
import org.exist.xquery.util.DocUtils;
3132
import org.exist.xquery.value.BooleanValue;
32-
import org.exist.xquery.value.FunctionReturnSequenceType;
33-
import org.exist.xquery.value.FunctionParameterSequenceType;
34-
import org.exist.xquery.value.Item;
3533
import org.exist.xquery.value.Sequence;
36-
import org.exist.xquery.value.SequenceType;
3734
import org.exist.xquery.value.Type;
3835

3936
import java.net.URI;
4037
import java.net.URISyntaxException;
4138

39+
import static org.exist.xquery.FunctionDSL.optParam;
40+
import static org.exist.xquery.FunctionDSL.returns;
41+
import static org.exist.xquery.functions.fn.FnModule.functionSignature;
42+
4243
/**
43-
* Implements the XQuery's fn:doc-available() function.
44+
* Implementation of the XPath fn:doc-available() function.
45+
* {@see https://www.w3.org/TR/xpath-functions-31/#func-doc-available}.
4446
*
45-
* @author <a href="mailto:[email protected]">Pierrick Brihaye</a>
46-
* @author wolf
47+
* @author <a href="mailto:[email protected]">Adam Retter</a>
4748
*/
48-
public class FunDocAvailable extends Function {
49-
50-
protected static final Logger logger = LogManager.getLogger(FunDocAvailable.class);
49+
public class FunDocAvailable extends BasicFunction {
5150

52-
public static final FunctionSignature signature =
53-
new FunctionSignature(
54-
new QName("doc-available", Function.BUILTIN_FUNCTION_NS),
55-
"Returns whether or not the document, $document-uri, " +
56-
"specified in the input sequence is available. " +
57-
XMLDBModule.ANY_URI,
58-
new SequenceType[]{
59-
new FunctionParameterSequenceType("document-uri", Type.STRING,
60-
Cardinality.ZERO_OR_ONE, "The document URI")
61-
},
62-
new FunctionReturnSequenceType(Type.BOOLEAN, Cardinality.EXACTLY_ONE,
63-
"true() if the document is available, false() otherwise"));
51+
public static final FunctionSignature FS_DOC_AVAILABLE = functionSignature(
52+
"doc-available",
53+
"The function returns true if and only if the function call fn:doc($uri) would return a document node.",
54+
returns(Type.BOOLEAN, "If a call on fn:doc($uri) would return a document node, this function returns true. In all other cases this function returns false."),
55+
optParam("uri", Type.STRING, "The URI to check for a document.")
56+
);
6457

65-
public FunDocAvailable(final XQueryContext context) {
58+
public FunDocAvailable(final XQueryContext context, final FunctionSignature signature) {
6659
super(context, signature);
6760
}
6861

6962
@Override
70-
public int getDependencies() {
71-
return Dependency.CONTEXT_SET;
72-
}
73-
74-
@Override
75-
public Sequence eval(final Sequence contextSequence, final Item contextItem)
76-
throws XPathException {
77-
if (context.getProfiler().isEnabled()) {
78-
context.getProfiler().start(this);
79-
context.getProfiler().message(this, Profiler.DEPENDENCIES,
80-
"DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
81-
if (contextSequence != null) {
82-
context.getProfiler().message(this, Profiler.START_SEQUENCES,
83-
"CONTEXT SEQUENCE", contextSequence);
84-
}
85-
if (contextItem != null) {
86-
context.getProfiler().message(this, Profiler.START_SEQUENCES,
87-
"CONTEXT ITEM", contextItem.toSequence());
88-
}
63+
public Sequence eval(final Sequence[] args, final Sequence contextSequence) throws XPathException {
64+
if (args.length == 0) {
65+
return BooleanValue.FALSE;
8966
}
9067

91-
Sequence result = BooleanValue.FALSE;
92-
final Sequence arg = getArgument(0).eval(contextSequence, contextItem);
93-
if (!arg.isEmpty()) {
94-
final String path = arg.itemAt(0).getStringValue();
95-
96-
try {
97-
new URI(path);
98-
} catch (final URISyntaxException e) {
99-
throw new XPathException(this, ErrorCodes.FODC0005, e.getMessage(), arg, e);
100-
}
101-
102-
try {
103-
result = BooleanValue.valueOf(DocUtils.isDocumentAvailable(this.context, path, this));
104-
} catch (final XPathException e) {
105-
result = BooleanValue.FALSE;
68+
final String uri = args[0].getStringValue();
69+
try {
70+
new URI(uri);
71+
} catch (final URISyntaxException e) {
72+
if (context.getXQueryVersion() == 31) {
73+
// XPath 3.1
74+
return BooleanValue.FALSE;
75+
} else {
76+
// XPath 2.0 and 3.0
77+
throw new XPathException(this, ErrorCodes.FODC0005, e.getMessage(), args[0], e);
10678
}
10779
}
10880

109-
if (context.getProfiler().isEnabled()) {
110-
context.getProfiler().end(this, "", result);
81+
try {
82+
return BooleanValue.valueOf(DocUtils.isDocumentAvailable(this.context, uri, this));
83+
} catch (final XPathException e) {
84+
return BooleanValue.FALSE;
11185
}
112-
113-
return result;
114-
}
115-
116-
@Override
117-
public void resetState(final boolean postOptimization) {
118-
super.resetState(postOptimization);
119-
getArgument(0).resetState(postOptimization);
12086
}
12187
}

exist-core/src/test/java/org/exist/xquery/functions/fn/DocTest.java

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,31 @@
11
/*
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
4+
*
5+
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
7+
*
8+
* Use of this software is governed by the Business Source License 1.1
9+
* included in the LICENSE file and at www.mariadb.com/bsl11.
10+
*
11+
* Change Date: 2028-04-27
12+
*
13+
* On the date above, in accordance with the Business Source License, use
14+
* of this software will be governed by the Apache License, Version 2.0.
15+
*
16+
* Additional Use Grant: Production use of the Licensed Work for a permitted
17+
* purpose. A Permitted Purpose is any purpose other than a Competing Use.
18+
* A Competing Use means making the Software available to others in a commercial
19+
* product or service that: substitutes for the Software; substitutes for any
20+
* other product or service we offer using the Software that exists as of the
21+
* date we make the Software available; or offers the same or substantially
22+
* similar functionality as the Software.
23+
*
24+
* NOTE: Parts of this file contain code from 'The eXist-db Authors'.
25+
* The original license header is included below.
26+
*
27+
* =====================================================================
28+
*
229
* eXist-db Open Source Native XML Database
330
* Copyright (C) 2001 The eXist-db Authors
431
*
@@ -68,10 +95,9 @@
6895
import java.net.URISyntaxException;
6996

7097
/**
71-
*
98+
* @author <a href="mailto:[email protected]">Adam Retter</a>
7299
* @author Joe Wicentowski
73100
* @author <a href="mailto:[email protected]">Dmitriy Shabanov</a>
74-
* @author Adam Retter
75101
*/
76102
public class DocTest {
77103

@@ -260,6 +286,25 @@ public void docAvailable_dynamicallyAvailableDocument_relativeUri() throws XPath
260286
}
261287
}
262288

289+
@Test
290+
public void docAvailableInPredicate() throws XPathException, EXistException, PermissionDeniedException {
291+
final BrokerPool pool = BrokerPool.getInstance();
292+
final String query = "('/db/test.xml', '/db/test/test.xml', '/db/non-existent.xml')[fn:doc-available(.)]";
293+
294+
try (final DBBroker broker = pool.getBroker()) {
295+
final XQueryContext context = new XQueryContext(pool);
296+
297+
final XQuery xqueryService = pool.getXQueryService();
298+
final CompiledXQuery compiled = xqueryService.compile(context, query);
299+
final Sequence result = xqueryService.execute(broker, compiled, null);
300+
301+
assertFalse(result.isEmpty());
302+
assertEquals(2, result.getItemCount());
303+
assertEquals("/db/test.xml", result.itemAt(0).getStringValue());
304+
assertEquals("/db/test/test.xml", result.itemAt(1).getStringValue());
305+
}
306+
}
307+
263308
private Either<DocumentImpl, org.exist.dom.persistent.DocumentImpl> asInMemoryDocument(final String doc) throws XPathException {
264309
try {
265310
final SAXAdapter saxAdapter = new SAXAdapter();

0 commit comments

Comments
 (0)