Skip to content

Commit 1eef586

Browse files
authored
Merge pull request #4473 from evolvedbinary/hotfix/local-name
Corrects issues with fn:local-name and unnecessary evaluation of path steps on empty sequences
2 parents 4074014 + 142d851 commit 1eef586

File tree

8 files changed

+57
-10
lines changed

8 files changed

+57
-10
lines changed

exist-core/src/main/java/org/exist/xquery/AbstractExpression.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,4 +187,9 @@ public Expression simplify() {
187187
public Expression getParent() {
188188
return null;
189189
}
190+
191+
@Override
192+
public boolean evalNextExpressionOnEmptyContextSequence() {
193+
return false;
194+
}
190195
}

exist-core/src/main/java/org/exist/xquery/DebuggableExpression.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,9 @@ public Expression simplify() {
194194
public Expression getParent() {
195195
return null;
196196
}
197+
198+
@Override
199+
public boolean evalNextExpressionOnEmptyContextSequence() {
200+
return false;
201+
}
197202
}

exist-core/src/main/java/org/exist/xquery/Expression.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,4 +255,13 @@ public interface Expression {
255255
public boolean allowMixedNodesInReturn();
256256

257257
public Expression getParent();
258+
259+
/**
260+
* Return true only if the next expression within a path expression
261+
* should be evaluated even when this expression returns an
262+
* empty sequence.
263+
*
264+
* @return true if the next expression should be evaluated, false otherwise.
265+
*/
266+
boolean evalNextExpressionOnEmptyContextSequence();
258267
}

exist-core/src/main/java/org/exist/xquery/PathExpr.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ public Sequence eval(Sequence contextSequence, final Item contextItem) throws XP
229229
//TODO : let the parser do it ? -pb
230230
boolean gotAtomicResult = false;
231231
Expression prev = null;
232-
for (Expression step : steps) {
232+
for (final Expression step : steps) {
233233
prev = expr;
234234
expr = step;
235235
context.getWatchDog().proceed(expr);
@@ -302,7 +302,22 @@ public Sequence eval(Sequence contextSequence, final Item contextItem) throws XP
302302
// expression with more than one step
303303
result.removeDuplicates();
304304
}
305+
306+
/**
307+
* If the result is an Empty Sequence, we don't need to process
308+
* any more steps as there is no Context Sequence for the next step!
309+
*
310+
* There is one exception to this rule, which is a TextConstructor
311+
* expression that only contains whitespace but has been configured
312+
* to strip-whitespace. In this instance the TextConstructor will
313+
* return true when {@link Expression#evalNextExpressionOnEmptyContextSequence()}
314+
* is called to indicate that.
315+
*/
316+
if (result.isEmpty() && !step.evalNextExpressionOnEmptyContextSequence()) {
317+
break;
318+
}
305319
}
320+
306321
if (!staticContext) {
307322
currentContext = result;
308323
}

exist-core/src/main/java/org/exist/xquery/TextConstructor.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,13 @@ public String getText() {
9696
public boolean allowMixedNodesInReturn() {
9797
return true;
9898
}
99+
100+
@Override
101+
public boolean evalNextExpressionOnEmptyContextSequence() {
102+
/*
103+
When this TextConstructor only contains whitespace but has been configured
104+
to strip-whitespace, return true so that the next expression is processed correctly.
105+
*/
106+
return isWhitespaceOnly && context.stripWhitespace();
107+
}
99108
}

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.exist.xquery.value.StringValue;
4040
import org.exist.xquery.value.Type;
4141
import org.w3c.dom.Node;
42+
import org.w3c.dom.ProcessingInstruction;
4243

4344
/**
4445
* Built-in function fn:local-name().
@@ -126,8 +127,14 @@ public Sequence eval(Sequence contextSequence, final Item contextItem) throws XP
126127
}
127128

128129
//TODO : how to improve performance ?
130+
final String localName;
129131
final Node n = ((NodeValue) item).getNode();
130-
final String localName = n.getLocalName();
132+
if (n.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
133+
localName = ((ProcessingInstruction) n).getTarget();
134+
} else {
135+
localName = n.getLocalName();
136+
}
137+
131138
if (localName != null) {
132139
result = new StringValue(this, localName);
133140
} else {

exist-core/src/test/java/org/exist/xquery/XQueryFunctionsTest.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -606,8 +606,7 @@ public void localName_contextItem_empty() throws XPathException, XMLDBException
606606
final ResourceSet result = existEmbeddedServer.executeQuery(
607607
"let $a := <a><b/></a>" +
608608
"return $a/b/c/fn:local-name()");
609-
final String r = (String) result.getResource(0).getContent();
610-
assertEquals("", r);
609+
assertEquals(0, result.getSize());
611610
}
612611

613612
@Test
@@ -657,8 +656,7 @@ public void name_contextItem_empty() throws XPathException, XMLDBException {
657656
final ResourceSet result = existEmbeddedServer.executeQuery(
658657
"let $a := <a><b/></a>" +
659658
"return $a/b/c/fn:name()");
660-
final String r = (String) result.getResource(0).getContent();
661-
assertEquals("", r);
659+
assertEquals(0, result.getSize());
662660
}
663661

664662
@Test
@@ -762,12 +760,11 @@ public void namespaceURI_contextItem() throws XPathException, XMLDBException {
762760
}
763761

764762
@Test
765-
public void namespaceURI_contextItem_empty() throws XPathException, XMLDBException {
763+
public void namespaceURI_contextItem_empty() throws XMLDBException {
766764
final ResourceSet result = existEmbeddedServer.executeQuery(
767765
"let $a := <a><b/></a>" +
768766
"return $a/exist:b/c/fn:namespace-uri()");
769-
final String r = (String) result.getResource(0).getContent();
770-
assertEquals("", r);
767+
assertEquals(0, result.getSize());
771768
}
772769

773770
@Test

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ function fnt:document-uri0_context() {
145145
};
146146

147147
declare
148-
%test:assertError("err:XPDY0002")
148+
%test:assertEmpty
149149
function fnt:document-uri0_context_empty() {
150150
root(collection('/db/fn-test')//bookies)/document-uri()
151151
};

0 commit comments

Comments
 (0)