[XQZone General] RE: passing sequences to xdmp:eval( )
Howard Katz
howardk at fatdog.com
Wed Dec 7 11:31:37 PST 2005
It turns out there's another downside to my workaround. Given the example
below, invoking
eval-node-test( $nodes, "starts-with( ., 'ca' )" )
returns all the nodes that pass the "starts-with() test". However, I also
want to be able to see which nodes *don't* pass the test and had expected to
be able to use the "except" operator to extract the difference, ie the "bad"
ones. In other words, I had expected this to work:
let $nodes:= ( <a>cat</a>, <b>dog</b>, <c>catalog</c> )
let $good-nodes := eval-node-test( $nodes, "starts-with( ., 'ca' )" )
return
<both>
<good-nodes>{ $good-nodes }</good-nodes>
<bad-nodes>{ $nodes except $good-nodes }</bad-nodes>
</both>
This fails however, with <bad-nodes> always turning out to be equal to the
original node sequence, not some subset of it. What is happening apparently
is that the $good-nodes being returned no longer have their original
identity, and the difference of the two simply returns the original node
sequence, because there's nothing in common any longer between $nodes and
$good-nodes.
So it looks like I'm doubly in need of another way of doing this. I could
stick unique @id identifiers on all nodes and generate the difference of the
two sequences using those, but that doesn't seem anywhere near as attractive
as using "except".
Any thoughts?
Howard
> -----Original Message-----
> From: Howard Katz [mailto:howardk at fatdog.com]
> Sent: December 7, 2005 9:18 AM
> To: 'General XQZone Discussion'
> Subject: passing sequences to xdmp:eval( )
>
> I have a series of boolean-returning query tests that are
> stored as strings, and I need to be able to apply these
> tests against a variety of node sequences, getting back the
> nodes that passed. Since the queries are strings, I'm using
> xdmp:eval(). This works ok, but I have to do a slight
> workaround to satisfy eval(), and I'm concerned about
> performance issues when I scale up to run the tests against
> very large sequences, say on the order of hundreds of
> thousands of nodes.
>
> Assume that one of the stored tests I want to run is
> 'starts-with( ., "ca" )'. If I was directly applying this
> test against the sequence, "(<a>cat</a>, <b>dog</b>,
> <c>catalog</c>)" (ie, not eval'ing it), I could say:
>
> let $seq := ( <a>cat</a>, <b>dog</b>, <c>catalog</c> )
> return
> $seq[ starts-with( ., "ca" ) ]
>
> and I'd get back the node sequence, ( <a>cat</a>,
> <c>catalog</c> ). So far so good.
>
> If the same query is now stored as a string and I'm using
> eval(), I'd similarly like to be able to say:
>
>
> define function eval-node-test( $nodes as element()+,
> $test as xs:string ) as element()*
> {
> let $query := concat( "define variable $seq as
> element() external ", "$seq[ ", $test, " ]" )
> return
> xdmp:eval( $query, ( xs:QName("seq"), $nodes ) )
> }
>
> let $nodes:= ( <a>cat</a>, <b>dog</b>, <c>catalog</c> )
> return
>
> eval-node-test( $nodes, "starts-with( ., 'ca' )" )
>
>
> This won't work however because the $nodes argument passed
> in '( xs:QName("seq"), $nodes )' can't be a sequence, only a
> singleton. This means that in order to use eval(),
>
> (1) I have to wrap the $nodes sequence in a temporary
> <temp-root/> wrapper, and
> (2) construct the last part of the query inside concat() as
> "$seq/* [ ", $test, ... ", rather than "$seq [ ", $test ... ".
>
> In other words,
>
> 1) To satisfy eval(), I have to hoist all my nodes into a
> temporarily constructed super-element, and
> 2) dereference every one of them again inside my query
>
> Since I potentially need to be able to run these tests
> against hundreds of thousands of nodes, I'm concerned about
> performance. Is that concern justified? And if is, is there
> a more efficient way of doing this?
>
> Howard
>
More information about the General
mailing list