Skip to content

Commit 6d8f45e

Browse files
committed
Implement fn:document-uri0
1 parent 09c3ff3 commit 6d8f45e

File tree

3 files changed

+91
-45
lines changed

3 files changed

+91
-45
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ public class FnModule extends AbstractInternalModule {
7171
new FunctionDef(FunDistinctValues.signatures[1], FunDistinctValues.class),
7272
new FunctionDef(FunDoc.signature, FunDoc.class),
7373
new FunctionDef(FunDocAvailable.signature, FunDocAvailable.class),
74-
new FunctionDef(FunDocumentURI.signature, FunDocumentURI.class),
74+
new FunctionDef(FunDocumentURI.FS_DOCUMENT_URI_0, FunDocumentURI.class),
75+
new FunctionDef(FunDocumentURI.FS_DOCUMENT_URI_1, FunDocumentURI.class),
7576
new FunctionDef(FunEmpty.signature, FunEmpty.class),
7677
new FunctionDef(FunEncodeForURI.signature, FunEncodeForURI.class),
7778
new FunctionDef(FunEndsWith.signatures[0], FunEndsWith.class),

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

Lines changed: 65 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -22,85 +22,107 @@
2222
package org.exist.xquery.functions.fn;
2323

2424
import org.exist.dom.persistent.NodeProxy;
25-
import org.exist.dom.QName;
2625
import org.exist.dom.memtree.DocumentImpl;
2726
import org.exist.xmldb.XmldbURI;
28-
import org.exist.xquery.Cardinality;
29-
import org.exist.xquery.Dependency;
30-
import org.exist.xquery.Function;
31-
import org.exist.xquery.FunctionSignature;
32-
import org.exist.xquery.Profiler;
33-
import org.exist.xquery.XPathException;
34-
import org.exist.xquery.XQueryContext;
27+
import org.exist.xquery.*;
3528
import org.exist.xquery.value.AnyURIValue;
36-
import org.exist.xquery.value.FunctionReturnSequenceType;
3729
import org.exist.xquery.value.FunctionParameterSequenceType;
3830
import org.exist.xquery.value.Item;
3931
import org.exist.xquery.value.NodeValue;
4032
import org.exist.xquery.value.Sequence;
41-
import org.exist.xquery.value.SequenceType;
4233
import org.exist.xquery.value.Type;
4334

35+
import static org.exist.xquery.FunctionDSL.*;
36+
import static org.exist.xquery.functions.fn.FnModule.functionSignature;
37+
4438
/**
4539
* @author wolf
4640
*/
4741
public class FunDocumentURI extends Function {
4842

49-
public final static FunctionSignature signature =
50-
new FunctionSignature(
51-
new QName("document-uri", Function.BUILTIN_FUNCTION_NS),
52-
"Returns the absolute URI of the resource from which the " +
53-
"document node $document-node was constructed. " +
54-
"If none such URI exists returns the empty sequence. " +
55-
"If $document-node is the empty sequence, returns the empty sequence.",
56-
new SequenceType[] {
57-
new FunctionParameterSequenceType("document-node", Type.NODE,
58-
Cardinality.ZERO_OR_ONE, "The document node")
59-
},
60-
new FunctionReturnSequenceType(Type.ANY_URI, Cardinality.ZERO_OR_ONE,
61-
"the document URI of $document-node")
62-
);
63-
64-
public FunDocumentURI(XQueryContext context) {
43+
private static final FunctionParameterSequenceType FS_PARAM_NODE = optManyParam("value", Type.NODE, "The document node.");
44+
45+
private static final String FS_DOCUMENT_URI = "document-uri";
46+
private static final String FS_DESCRIPTION = "Returns the URI of a resource where a document can be found, if available.";
47+
48+
private static final String FS_RETURN_DESCRIPTION = "The URI of a resource.";
49+
static final FunctionSignature FS_DOCUMENT_URI_0 = functionSignature(
50+
FS_DOCUMENT_URI,
51+
FS_DESCRIPTION,
52+
returnsOpt(Type.ANY_URI, FS_RETURN_DESCRIPTION)
53+
);
54+
55+
static final FunctionSignature FS_DOCUMENT_URI_1 = functionSignature(
56+
FS_DOCUMENT_URI,
57+
FS_DESCRIPTION,
58+
returnsOpt(Type.ANY_URI, FS_RETURN_DESCRIPTION),
59+
FS_PARAM_NODE
60+
);
61+
62+
public FunDocumentURI(final XQueryContext context, final FunctionSignature signature) {
6563
super(context, signature);
6664
}
6765

6866
/* (non-Javadoc)
6967
* @see org.exist.xquery.Expression#eval(org.exist.xquery.StaticContext, org.exist.dom.persistent.DocumentSet, org.exist.xquery.value.Sequence, org.exist.xquery.value.Item)
7068
*/
71-
public Sequence eval(Sequence contextSequence, Item contextItem)
72-
throws XPathException {
69+
public Sequence eval(final Sequence contextSequence, final Item contextItem) throws XPathException {
7370
if (context.getProfiler().isEnabled()) {
7471
context.getProfiler().start(this);
7572
context.getProfiler().message(this, Profiler.DEPENDENCIES,
76-
"DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
77-
if (contextSequence != null)
78-
{context.getProfiler().message(this, Profiler.START_SEQUENCES,
79-
"CONTEXT SEQUENCE", contextSequence);}
80-
if (contextItem != null)
81-
{context.getProfiler().message(this, Profiler.START_SEQUENCES,
82-
"CONTEXT ITEM", contextItem.toSequence());}
73+
"DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
74+
if (contextSequence != null) {
75+
context.getProfiler().message(this, Profiler.START_SEQUENCES,"CONTEXT SEQUENCE", contextSequence);
76+
}
77+
if (contextItem != null) {
78+
context.getProfiler().message(this, Profiler.START_SEQUENCES,"CONTEXT ITEM", contextItem.toSequence());
79+
}
80+
}
81+
82+
final boolean isContextItem = (contextItem != null);
83+
84+
if(!isContextItem && getArgumentCount()==0){
85+
// Bug in eXist-db? the 0-parameter function is invoked
86+
// which effectively means that the zero-argument function is active.
87+
throw new XPathException(this, ErrorCodes.XPDY0002, "Context item is absent ");
8388
}
84-
final Sequence seq = getArgument(0).eval(contextSequence, contextItem);
89+
90+
// Get sequence from contextItem or from parameter
91+
final Sequence seq = (isContextItem)
92+
? contextItem.toSequence()
93+
: getArgument(0).eval(contextSequence, contextItem);
94+
95+
if (isContextItem && seq.isEmpty()) {
96+
// This is the actual empty context item check
97+
throw new XPathException(this, ErrorCodes.XPDY0002, "Context item is absent.");
98+
}
99+
100+
if (isContextItem && !Type.subTypeOf(seq.getItemType(), Type.NODE) ) {
101+
// If context item is provided, it must be a node
102+
throw new XPathException(this, ErrorCodes.XPTY0004, "Context item is not a node.");
103+
}
104+
85105
Sequence result = Sequence.EMPTY_SEQUENCE;
86106
if (!seq.isEmpty()) {
87107
final NodeValue value = (NodeValue) seq.itemAt(0);
88-
if (value.getImplementationType() == NodeValue.PERSISTENT_NODE) {
108+
if (value.getImplementationType() == NodeValue.PERSISTENT_NODE) {
89109
final NodeProxy node = (NodeProxy) value;
90-
//Returns the empty sequence if the node is not a document node.
110+
//Returns the empty sequence if the node is not a document node.
91111
if (node.isDocument()) {
92-
final XmldbURI path = node.getOwnerDocument().getURI();
112+
final XmldbURI path = node.getOwnerDocument().getURI();
93113
result = new AnyURIValue(path);
94114
}
115+
95116
} else {
96-
if (value instanceof DocumentImpl &&
97-
((DocumentImpl)value).getDocumentURI() != null) {
117+
if (value instanceof DocumentImpl && ((DocumentImpl)value).getDocumentURI() != null) {
98118
result = new AnyURIValue(((DocumentImpl)value).getDocumentURI());
99119
}
100120
}
101121
}
102-
if (context.getProfiler().isEnabled())
103-
{context.getProfiler().end(this, "", result);}
122+
123+
if (context.getProfiler().isEnabled()) {
124+
context.getProfiler().end(this, "", result);
125+
}
104126
return result;
105127
}
106128
}

exist-core/src/test/xquery/fn.xql

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ function fnt:cleanup() {
4848
xmldb:remove("/db/fn-test")
4949
};
5050

51-
declare
51+
declare
5252
%test:args("NFC")
5353
%test:assertEquals(6, 6)
5454
%test:args("NFD")
@@ -126,3 +126,26 @@ function fnt:tokenize-onearg($str as xs:string) {
126126
tokenize($str)
127127
};
128128

129+
declare
130+
%test:assertEquals("/db/fn-test/test.xml")
131+
function fnt:document-uri0() {
132+
root(collection('/db/fn-test')//book)/document-uri()
133+
};
134+
135+
declare
136+
%test:assertError("err:XPDY0002")
137+
function fnt:document-uri0_empty() {
138+
root(collection('/db/fn-test')//bookies)/document-uri()
139+
};
140+
141+
declare
142+
%test:assertEquals("/db/fn-test/test.xml")
143+
function fnt:document-uri1() {
144+
document-uri(root(collection('/db/fn-test')//book))
145+
};
146+
147+
declare
148+
%test:assertEmpty
149+
function fnt:document-uri1_empty() {
150+
document-uri(root(collection('/db/fn-test')//bookies))
151+
};

0 commit comments

Comments
 (0)