Skip to content

Commit 0f09d83

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

File tree

4 files changed

+119
-82
lines changed

4 files changed

+119
-82
lines changed

exist-core/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,7 @@
753753
<include>src/main/java/org/exist/util/JREUtil.java</include>
754754
<include>src/main/java/org/exist/util/OSUtil.java</include>
755755
<include>src/main/java/org/exist/util/StringUtil.java</include>
756+
<include>src/main/java/org/exist/xquery/functions/fn/FunDocAvailable.java</include>
756757
<include>src/test/java/org/exist/xquery/ImportFromPkgTest.java</include>
757758
<include>src/test/java/org/exist/xquery/WatchdogTest.java</include>
758759
<include>src/test/java/org/exist/xquery/value/DateTimeTypesTest.java</include>
@@ -943,6 +944,8 @@
943944
<include>src/main/java/org/exist/management/impl/JMXAgent.java</include>
944945
<include>src/test/java/org/exist/xmldb/CreateCollectionsTest.java</include>
945946
<include>src/test/java/org/exist/xquery/XQueryFunctionsTest.java</include>
947+
<include>src/test/java/org/exist/xquery/functions/fn/DocTest.java</include>
948+
<include>src/main/java/org/exist/xquery/functions/fn/FnModule.java</include>
946949
<include>src/main/java/org/exist/xquery/functions/fn/FunBaseURI.java</include>
947950
<include>src/main/java/org/exist/xquery/functions/fn/FunParseIetfDate.java</include>
948951
<include>src/main/java/org/exist/xquery/functions/fn/FunTrace.java</include>
@@ -1127,7 +1130,9 @@
11271130
<exclude>src/main/java/org/exist/xquery/UserDefinedFunction.java</exclude>
11281131
<exclude>src/test/java/org/exist/xquery/WatchdogTest.java</exclude>
11291132
<exclude>src/main/java/org/exist/xquery/XQueryContext.java</exclude>
1133+
<exclude>src/main/java/org/exist/xquery/functions/fn/FnModule.java</exclude>
11301134
<exclude>src/main/java/org/exist/xquery/functions/fn/FunDeepEqual.java</exclude>
1135+
<exclude>src/main/java/org/exist/xquery/functions/fn/FunDocAvailable.java</exclude>
11311136
<exclude>src/main/java/org/exist/xquery/functions/fn/FunUriCollection.java</exclude>
11321137
<exclude>src/main/java/org/exist/xquery/functions/fn/FunBaseURI.java</exclude>
11331138
<exclude>src/main/java/org/exist/xquery/functions/fn/FunParseIetfDate.java</exclude>
@@ -1251,6 +1256,7 @@
12511256
<exclude>src/test/java/org/exist/xquery/ImportModuleTest.java</exclude>
12521257
<exclude>src/main/java/org/exist/xquery/Materializable.java</exclude>
12531258
<exclude>src/test/java/org/exist/xquery/XQueryContextAttributesTest.java</exclude>
1259+
<exclude>src/test/java/org/exist/xquery/functions/fn/DocTest.java</exclude>
12541260
<exclude>src/main/java/org/exist/xquery/functions/map/MapType.java</exclude>
12551261
<exclude>src/test/java/org/exist/xquery/functions/session/AbstractSessionTest.java</exclude>
12561262
<exclude>src/test/java/org/exist/xquery/functions/xmldb/AbstractXMLDBTest.java</exclude>

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

Lines changed: 26 additions & 1 deletion
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
*
@@ -33,6 +57,7 @@
3357
/**
3458
* Module function definitions for xpath-functions module.
3559
*
60+
* @author <a href="mailto:[email protected]">Adam Retter</a>
3661
* @author <a href="mailto:[email protected]">Wolfgang Meier</a>
3762
* @author ljo
3863
*/
@@ -73,7 +98,7 @@ public class FnModule extends AbstractInternalModule {
7398
new FunctionDef(FunDistinctValues.signatures[0], FunDistinctValues.class),
7499
new FunctionDef(FunDistinctValues.signatures[1], FunDistinctValues.class),
75100
new FunctionDef(FunDoc.signature, FunDoc.class),
76-
new FunctionDef(FunDocAvailable.signature, FunDocAvailable.class),
101+
new FunctionDef(FunDocAvailable.FS_DOC_AVAILABLE, FunDocAvailable.class),
77102
new FunctionDef(FunDocumentURI.FS_DOCUMENT_URI_0, FunDocumentURI.class),
78103
new FunctionDef(FunDocumentURI.FS_DOCUMENT_URI_1, FunDocumentURI.class),
79104
new FunctionDef(FunElementWithId.FS_ELEMENT_WITH_ID_SIGNATURES[0], FunElementWithId.class),
Lines changed: 43 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
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
*
88
* This library is free software; you can redistribute it and/or
99
* 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.
10+
* License as published by the Free Software Foundation; version 2.1.
1211
*
1312
* This library is distributed in the hope that it will be useful,
1413
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -21,101 +20,66 @@
2120
*/
2221
package org.exist.xquery.functions.fn;
2322

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;
23+
import org.exist.xquery.BasicFunction;
24+
import org.exist.xquery.ErrorCodes;
25+
import org.exist.xquery.FunctionSignature;
26+
import org.exist.xquery.XPathException;
27+
import org.exist.xquery.XQueryContext;
3028
import org.exist.xquery.util.DocUtils;
3129
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;
3530
import org.exist.xquery.value.Sequence;
36-
import org.exist.xquery.value.SequenceType;
3731
import org.exist.xquery.value.Type;
3832

3933
import java.net.URI;
4034
import java.net.URISyntaxException;
4135

36+
import static org.exist.xquery.FunctionDSL.optParam;
37+
import static org.exist.xquery.FunctionDSL.returns;
38+
import static org.exist.xquery.functions.fn.FnModule.functionSignature;
39+
4240
/**
43-
* Implements the XQuery's fn:doc-available() function.
41+
* Implementation of the XPath fn:doc-available() function.
42+
* See <a href="https://www.w3.org/TR/xpath-functions-31/#func-doc-available">14.6.2 fn:doc-available</a> in the
43+
* W3C XPath and XQuery Functions and Operators 3.1 specification.
4444
*
45-
* @author <a href="mailto:[email protected]">Pierrick Brihaye</a>
46-
* @author wolf
45+
* @author <a href="mailto:[email protected]">Adam Retter</a>
4746
*/
48-
public class FunDocAvailable extends Function {
47+
public class FunDocAvailable extends BasicFunction {
4948

50-
protected static final Logger logger = LogManager.getLogger(FunDocAvailable.class);
49+
public static final FunctionSignature FS_DOC_AVAILABLE = functionSignature(
50+
"doc-available",
51+
"The function returns true if and only if the function call fn:doc($uri) would return a document node.",
52+
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."),
53+
optParam("uri", Type.STRING, "The URI to check for a document.")
54+
);
5155

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"));
64-
65-
public FunDocAvailable(final XQueryContext context) {
56+
public FunDocAvailable(final XQueryContext context, final FunctionSignature signature) {
6657
super(context, signature);
6758
}
6859

6960
@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-
}
61+
public Sequence eval(final Sequence[] args, final Sequence contextSequence) throws XPathException {
62+
if (args.length == 0) {
63+
return BooleanValue.FALSE;
8964
}
9065

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;
66+
final String uri = args[0].getStringValue();
67+
try {
68+
new URI(uri);
69+
} catch (final URISyntaxException e) {
70+
if (context.getXQueryVersion() == 31) {
71+
// XPath 3.1
72+
return BooleanValue.FALSE;
73+
} else {
74+
// XPath 2.0 and 3.0
75+
throw new XPathException(this, ErrorCodes.FODC0005, e.getMessage(), args[0], e);
10676
}
10777
}
10878

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

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

Lines changed: 44 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
*
@@ -68,10 +92,9 @@
6892
import java.net.URISyntaxException;
6993

7094
/**
71-
*
95+
* @author <a href="mailto:[email protected]">Adam Retter</a>
7296
* @author Joe Wicentowski
7397
* @author <a href="mailto:[email protected]">Dmitriy Shabanov</a>
74-
* @author Adam Retter
7598
*/
7699
public class DocTest {
77100

@@ -260,6 +283,25 @@ public void docAvailable_dynamicallyAvailableDocument_relativeUri() throws XPath
260283
}
261284
}
262285

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

0 commit comments

Comments
 (0)