eXist-db / exist

eXist Native XML Database and Application Platform
https://exist-db.org
GNU Lesser General Public License v2.1
428 stars 179 forks source link

Unary (map) lookup in function call in predicate fails #2364

Open adamretter opened 5 years ago

adamretter commented 5 years ago

The following query should return the second map, instead we get an error XPST0003. This does work in BaseX and Saxon, but not in eXist-db. Appears to be a parser error.

Tested on eXist-db 5.0.0-RC6

let $ms := (
    map {
        "headers": (
            map {
                "name": "Content-Disposition",
                "value": 'filename="bob"'
            }
        )
    },
    map {
        "headers": (
            map {
                "name": "Content-Disposition",
                "value": 'filename="fred"'
            },
            map {
                "name": "Content-Type",
                "value": 'application/xml'
            }
        )
    }
)
return

$ms[not(empty(?headers[fn:matches(?value, 'filename="fred"')]))]
duncdrum commented 5 years ago

is this a separate problem from #2205, i can't really tell?

adamretter commented 5 years ago

@duncdrum yes, it's different.

line-o commented 5 years ago

It seems the parser already chokes on the implicit context element .?headers at least changes the error message.

The verbose equivalent of the code does run

filter($ms, function ($m) {
    not(empty(
        filter($m?headers, function ($h) { 
            matches($h?value, 'filename="fred"')})))})
adamretter commented 5 years ago

@line-o Er.. I don't use . in the code above?!?

line-o commented 5 years ago

@adamretter yes, doing that just changes the error. That was all I wanted to add.

I tested two simplified queries:

$ms[not(empty(?headers))]

error found while executing expression: org.exist.xquery.XPathException: err:XPST0003 expecting closing parenthesis ')', found 'headers' [at line ...]

vs

$ms[not(empty(.?headers))]

Unexpectedly received 2 parameter(s) in call to function 'empty()'. Defined function signatures are: empty($items as item()*) xs:boolean

line-o commented 5 years ago

I am also wondering, if the same syntax for filtering node sets //a[.] also applies to sequences of maps, but I could not find anything. The xquery spec does refer to node-sets only, it seems.

@adamretter Maybe I am missing something, can you give me a pointer?

line-o commented 5 years ago

I can confirm it works in BaseX. So do both of the simplified queries, I posted above.

line-o commented 4 years ago

exist 5.3.0-SNAPSHOT is affected

The originally reported issue seems to be limited to map lookups with implicit context passed to function calls inside of predicates.

(map {"f": 1}, map {"f": 2})[string(?f) eq '1']

whereas this works

(map {"f": 1}, map {"f": 2})[?f > 1]
line-o commented 2 years ago

With the changes to the XQuery parser included in eXist 5.3.0 you can write: $ms[?headers[?value ! matches(., 'filename="fred"')] => exists()]

which is further proof that the unary lookup passed to a function call inside a predicate is the root cause of this issue.

line-o commented 2 years ago

and $ms[not(empty(.?headers[matches(.?value, 'filename="fred"')]))] returns the expected result.