Open xatapult opened 5 years ago
Similarly, these expressions return the same error when they should not:
(true(), false())[not(.)]
(1, 2)[not(.)]
("a", "b")[not(.)]
The full error message:
err:FORG0006 effectiveBooleanValue: first item of '(a, b)' is not a node, and sequence length > 1 [source: xquery version "3.1"; ("a", "b")[not(.)]]
This error message is incorrect in two respects:
(true(), false())
case should trigger rule 3; ("a", "b")
by rule 4; and (1, 2)
by rule 5. So I took a quick look into this. Unfortunately the root of the problem is that eXist-db's parser and XQuery engine does not correctly understand .
i.e. the Context Item, instead it treats it as self::node()
with a bunch of hacks for when it might actually mean the context item.
There are two hacks that I could implement to fix this:
Commenting out lines 281-296 of Predicate.java
. This disables an optimisation, and gives us the correct result, but also will make other boolean expressions where the context sequence is not required slower as they will have to be evaluated for every item in the context sequence.
LocationStep.java
line 108: Removing the !this.inPredicate
expression which forces every .
or self::node()
to have a dependency on the context item. Whilst this would fix our issue with the Context Item, unfortunately this will also slow down expressions which genuinely use self::node()
.
The correct fix is to correct the XQuery Parser so that it correctly differentiates between self::node()
and the .
(Context Item) when constructing the AST. Next we need to modify the XQuery engine so that it knows what a Context Item is.
This is not a small piece of work, and as the existing XQuery Parser is outdated (Antlr2) and contains many other lurking issue, I think it is unlikely I will fix this personally. My efforts are more focued on a new XQuery Parser and Engine. However, anyone else is welcome to take a stab at fixing it in eXist-db...
@wolfgangmm any comments, perhaps you see an alternative path for fixing this?
eXist handles fn:not
in a particular way by trying to evaluate it as a set operation. Obviously this approach is wrongly applied here. A naive fix would likely result in many expressions becoming slower by an order of magnitude, so we need to be careful here. We'll keep this issue open, but fixing will take considerable time.
As Erik mentions, the temporary workaround is: count((true(), false(), false())[. eq false()])
I just found out that wrapping fn:not()
in a function works, too.
declare function local:wrappedNot($a) { not($a) };
(true(), true(), true(), false(), true())[local:wrappedNot(.)]
I created some tests on my way to this discovery. If you think they - or some of them - are useful, I can prepare a PR.
yes please if you could create a pr with both pending test and some that are passing like the wrapped function thingy that would be great. If you could also add some xqdoc comments with a link to the issue number that would be nice, thx.
What is the problem
The
not()
function used in a predicate on a boolean sequence fails... I'm trying to count the number of false or true entries in a sequence of booleans.count((true(), false(), false())[not(.)])
fails with the message: item of '(true, false, false)...' is not a node, and sequence length > 1count((true(), false(), false())[. eq false()])
workscount((true(), false(), false())[.])
worksNow 1.i. looks like a bug. In XSLT (Saxon) it simply works.
What did you expect
That this expression
count((true(), false(), false())[not(.)])
works as expected and as it does in Saxon.Describe how to reproduce or add a test
Run the attached XQuery
Context information