Screenshot instructions:
Windows
Mac
Red Hat Linux
Ubuntu
Click URL instructions:
Rightclick on ad, choose "Copy Link", then paste here →
(This may not be possible with some types of ads)
From: W.S. Hager <wshager@gm...>  20130828 14:17:54
Attachments:
Message as HTML

Hi, I've been looking at a way to make node selections based on xpath strings. In other words, I want to translate arbitrary pieces of xpath into higherorder functions. Please consider the example: $list[type eq 'Paperback' and (empty(date) or date > '20130101')] This is pretty straightforward in xpath. However, in my app I want to reassemble the xpath expression from query parameters. I currently use util:eval to evaluate the stuff between square brackets above. However, eval is evil and the performance is not good enough for more complex expression. So I thought I'd try to compose the expression out of higherorder functions. Please consider this xquery 3.0: declare function local:and($a, $b) { $a and $b }; declare function local:or($a, $b) { $a or $b }; declare function local:eq($p, $t) { $p eq $t }; declare function local:gt($p, $t) { $p gt $t }; declare function local:comp($x as node()*,$p as xs:string,$t as xs:string, $f as function) { $x/*[name(.) = $p][$f(.,$t)] }; declare function local:comp($x as node()*,$p as xs:string,$f as function) { $x/*[name(.) = $p][$f(.)] }; return collection("/db/titles")//root[local:and( local:comp(.,'type','Paperback',local:eq#2), local:or( local:comp(.,'date',empty#1), local:comp(.,'date','20130101',local:gt#2) ))] However, performance is even worse than util:eval. Is there any way to improve upon "util:eval with a concatenated xpath string", or are there other viable approaches closer to the one above? Thanks. PS. as you can see there's more to improve in the above, because the functions are still stated within square brackets to prevent forloops.  W.S. Hager Lagua Web Solutions http://lagua.nl 
From: <wolfgang@ex...>  20130828 18:09:51

Hi, > I've been looking at a way to make node selections based on xpath strings. > In other words, I want to translate arbitrary pieces of xpath into > higherorder functions. While this is an interesting and challenging experiment, I don't think it will be fast. Splitting the XPath into many separate function calls makes it more or less impossible for the query engine to apply query rewritings and use indexes in an efficient way. > Please consider the example: > > $list[type eq 'Paperback' and (empty(date) or date > '20130101')] > > This is pretty straightforward in xpath. However, in my app I want to > reassemble the xpath expression from query parameters. I currently use > util:eval to evaluate the stuff between square brackets above. > > However, eval is evil and the performance is not good enough for more > complex expression. So I thought I'd try to compose the expression out of > higherorder functions. The disadvantage of eval is that it has to initialize a separate XQuery context. If you have to do that a hundred times in a single query, it will consume a lot of time. Calling eval just a dozen times or so should be ok though and the overhead for the context switch is small. What is more important: the XPath expression within the eval call should be optimizable, which means it should include all relevant parts of the XPath. As I understand your example, you are only passing the filter expression to eval? This is probably slow. For optimizations it would be better to evaluate the entire XPath within the eval in one go: util:eval("$list[type eq 'Paperback' and (empty(date) or date > '20130101')]") As a further improvement I would also split the "and" expression into two filters, which makes it easier for the query engine to rewrite: util:eval("$list[type eq 'Paperback'][empty(date) or date > '20130101']") Wolfgang 
From: W.S. Hager <wshager@gm...>  20130828 19:06:43
Attachments:
Message as HTML

Hi Wolfgang, Thanks for your answer. I do eval the xpath expression like you mentioned, and I will try to split the and into separate square brackets. Thanks, Wouter 2013/8/28 <wolfgang@...> > Hi, > > > I've been looking at a way to make node selections based on xpath > strings. > > In other words, I want to translate arbitrary pieces of xpath into > > higherorder functions. > > While this is an interesting and challenging experiment, I don't think it > will be fast. Splitting the XPath into many separate function calls makes > it more or less impossible for the query engine to apply query rewritings > and use indexes in an efficient way. > > > Please consider the example: > > > > $list[type eq 'Paperback' and (empty(date) or date > '20130101')] > > > > This is pretty straightforward in xpath. However, in my app I want to > > reassemble the xpath expression from query parameters. I currently use > > util:eval to evaluate the stuff between square brackets above. > > > > However, eval is evil and the performance is not good enough for more > > complex expression. So I thought I'd try to compose the expression out of > > higherorder functions. > > The disadvantage of eval is that it has to initialize a separate XQuery > context. If you have to do that a hundred times in a single query, it will > consume a lot of time. Calling eval just a dozen times or so should be ok > though and the overhead for the context switch is small. > > What is more important: the XPath expression within the eval call should > be optimizable, which means it should include all relevant parts of the > XPath. As I understand your example, you are only passing the filter > expression to eval? This is probably slow. For optimizations it would be > better to evaluate the entire XPath within the eval in one go: > > util:eval("$list[type eq 'Paperback' and (empty(date) or date > > '20130101')]") > > As a further improvement I would also split the "and" expression into two > filters, which makes it easier for the query engine to rewrite: > > util:eval("$list[type eq 'Paperback'][empty(date) or date > '20130101']") > > > Wolfgang  W.S. Hager Lagua Web Solutions http://lagua.nl 
From: Adam Retter <adam@ex...>  20130828 21:21:54

I think I am correct in saying that the functional approach that you want to achieve is possible using currying. A predicate is basically an expression that evaluates to an `effective boolean value`, as such you can use any function that returns true() or false(). Such a function can be built dynamically by using partial function application (to achieve currying) and function passing. I have no idea of the performance profile of this approach, however I would guess that the optimiser could not yet do anything with this approach. But if your really careful, you might not need the optimiser anyway ;) I would love to hear Wolfgang's thoughts on this... I think the downside to the approach below, is that each thing in the context ($ctx) may need to be checked against your evaluation, whereas inside a predicate with the optimiser, I guess as soon as the first true result is found when working with a sequence it can stop evaluation. This may still hold, I am not so clear on some of the internals of eXist's optimisation strategy. Basically you can dynamically build your predicate like so  xquery version "3.0"; declare function local:and($ctx as item()*, $left as function(item()*) as xs:boolean*, $right as function(item()*) as xs:boolean*) as xs:boolean { $left($ctx) = true() and $right($ctx) = true() }; declare function local:or($ctx as item()*, $left as function(item()*) as xs:boolean*, $right as function(item()*) as xs:boolean*) as xs:boolean { $left($ctx) = true() or $right($ctx) = true() }; declare function local:predicate($ctx as item()*, $fn as function(item()*) as xs:boolean) as xs:boolean { $fn($ctx) = true() }; You could then apply your predicate using  $list[local:predicate(., local:and(?, function($ctx) { $ctx/type = "Paperback" }, local:or(?, function($ctx) { $ctx/empty(date) }, function($ctx) { $ctx/date > '20130101' }) ) )] The three anonymous inline functions above that are effectively your equality tests, could easily be generated by further function calls, I have simply inlined them to keep the example simple. For testing this, I used the following  let $data := ( <container> <type>Paperback</type> <date>20130102</date> </container>) return local:predicate( $data, local:and(?, function($ctx) { $ctx/type = "Paperback" }, local:or(?, function($ctx) { $ctx/empty(date) }, function($ctx) { $ctx/date > '20130101' }) ) ) You may also be interested in this  https://github.com/jpcs/functional.xq I would think that the curry and compose functions could prove useful to you. ...It's just "Turtles all the way down" ;) On 28 August 2013 15:17, W.S. Hager <wshager@...> wrote: > Hi, > > I've been looking at a way to make node selections based on xpath strings. > In other words, I want to translate arbitrary pieces of xpath into > higherorder functions. > > Please consider the example: > > $list[type eq 'Paperback' and (empty(date) or date > '20130101')] > > This is pretty straightforward in xpath. However, in my app I want to > reassemble the xpath expression from query parameters. I currently use > util:eval to evaluate the stuff between square brackets above. > > However, eval is evil and the performance is not good enough for more > complex expression. So I thought I'd try to compose the expression out of > higherorder functions. > > Please consider this xquery 3.0: > > declare function local:and($a, $b) { > $a and $b > }; > > declare function local:or($a, $b) { > $a or $b > }; > > declare function local:eq($p, $t) { > $p eq $t > }; > > declare function local:gt($p, $t) { > $p gt $t > }; > > declare function local:comp($x as node()*,$p as xs:string,$t as xs:string, > $f as function) { > $x/*[name(.) = $p][$f(.,$t)] > }; > > declare function local:comp($x as node()*,$p as xs:string,$f as function) { > $x/*[name(.) = $p][$f(.)] > }; > > return collection("/db/titles")//root[local:and( > local:comp(.,'type','Paperback',local:eq#2), > local:or( > local:comp(.,'date',empty#1), > local:comp(.,'date','20130101',local:gt#2) > ))] > > > However, performance is even worse than util:eval. Is there any way to > improve upon "util:eval with a concatenated xpath string", or are there > other viable approaches closer to the one above? > > Thanks. > > PS. as you can see there's more to improve in the above, because the > functions are still stated within square brackets to prevent forloops. > >  > > W.S. Hager > Lagua Web Solutions > http://lagua.nl > > >  > Learn the latestVisual Studio 2012, SharePoint 2013, SQL 2012, more! > Discover the easy way to master current and previous Microsoft technologies > and advance your career. Get an incredible 1,500+ hours of stepbystep > tutorial videos with LearnDevNow. Subscribe today and save! > http://pubads.g.doubleclick.net/gampad/clk?id=58040911&iu=/4140/ostg.clktrk > _______________________________________________ > Existopen mailing list > Existopen@... > https://lists.sourceforge.net/lists/listinfo/existopen >  Adam Retter eXist Developer { United Kingdom } adam@... irc://irc.freenode.net/existdb 
From: Adam Retter <adam@ex...>  20130828 21:26:43

I just realised that for an even more natural syntax, you could in fact use declared variables assigned to anonymous instead of declared functions for the logic, i.e.: declare variable $or := function($ctx as item()*, $left as function(item()*) as xs:boolean*, $right as function(item()*) as xs:boolean*) as xs:boolean { $left($ctx) = true() or $right($ctx) = true() }; declare variable $and := function($ctx as item()*, $left as function(item()*) as xs:boolean*, $right as function(item()*) as xs:boolean*) as xs:boolean { $left($ctx) = true() and $right($ctx) = true() }; declare variable $p := function($ctx as item()*, $fn as function(item()*) as xs:boolean) as xs:boolean { $fn($ctx) = true() }; $list[$p(., $and(?, function($ctx) { $ctx/type = "Paperback" }, $or(?, function($ctx) { $ctx/empty(date) }, function($ctx) { $ctx/date > '20130101' }) ) )] Cheers Adam. On 28 August 2013 22:21, Adam Retter <adam@...> wrote: > I think I am correct in saying that the functional approach that you > want to achieve is possible using currying. A predicate is basically > an expression that evaluates to an `effective boolean value`, as such > you can use any function that returns true() or false(). Such a > function can be built dynamically by using partial function > application (to achieve currying) and function passing. > > I have no idea of the performance profile of this approach, however I > would guess that the optimiser could not yet do anything with this > approach. But if your really careful, you might not need the optimiser > anyway ;) I would love to hear Wolfgang's thoughts on this... > > I think the downside to the approach below, is that each thing in the > context ($ctx) may need to be checked against your evaluation, whereas > inside a predicate with the optimiser, I guess as soon as the first > true result is found when working with a sequence it can stop > evaluation. This may still hold, I am not so clear on some of the > internals of eXist's optimisation strategy. > > Basically you can dynamically build your predicate like so  > > xquery version "3.0"; > > declare function local:and($ctx as item()*, $left as function(item()*) > as xs:boolean*, $right as function(item()*) as xs:boolean*) as > xs:boolean { > $left($ctx) = true() and $right($ctx) = true() > }; > > declare function local:or($ctx as item()*, $left as function(item()*) > as xs:boolean*, $right as function(item()*) as xs:boolean*) as > xs:boolean { > $left($ctx) = true() or $right($ctx) = true() > }; > > declare function local:predicate($ctx as item()*, $fn as > function(item()*) as xs:boolean) as xs:boolean { > $fn($ctx) = true() > }; > > You could then apply your predicate using  > > $list[local:predicate(., > local:and(?, > function($ctx) { $ctx/type = "Paperback" }, > local:or(?, function($ctx) { $ctx/empty(date) }, > function($ctx) { $ctx/date > '20130101' }) > ) > )] > > The three anonymous inline functions above that are effectively your > equality tests, could easily be generated by further function calls, I > have simply inlined them to keep the example simple. > > For testing this, I used the following  > > let $data := ( > <container> > <type>Paperback</type> > <date>20130102</date> > </container>) return > > local:predicate( > $data, > local:and(?, > function($ctx) { $ctx/type = "Paperback" }, > local:or(?, function($ctx) { $ctx/empty(date) }, > function($ctx) { $ctx/date > '20130101' }) > ) > ) > > > You may also be interested in this  https://github.com/jpcs/functional.xq > I would think that the curry and compose functions could prove useful to you. > > ...It's just "Turtles all the way down" ;) > > > > On 28 August 2013 15:17, W.S. Hager <wshager@...> wrote: >> Hi, >> >> I've been looking at a way to make node selections based on xpath strings. >> In other words, I want to translate arbitrary pieces of xpath into >> higherorder functions. >> >> Please consider the example: >> >> $list[type eq 'Paperback' and (empty(date) or date > '20130101')] >> >> This is pretty straightforward in xpath. However, in my app I want to >> reassemble the xpath expression from query parameters. I currently use >> util:eval to evaluate the stuff between square brackets above. >> >> However, eval is evil and the performance is not good enough for more >> complex expression. So I thought I'd try to compose the expression out of >> higherorder functions. >> >> Please consider this xquery 3.0: >> >> declare function local:and($a, $b) { >> $a and $b >> }; >> >> declare function local:or($a, $b) { >> $a or $b >> }; >> >> declare function local:eq($p, $t) { >> $p eq $t >> }; >> >> declare function local:gt($p, $t) { >> $p gt $t >> }; >> >> declare function local:comp($x as node()*,$p as xs:string,$t as xs:string, >> $f as function) { >> $x/*[name(.) = $p][$f(.,$t)] >> }; >> >> declare function local:comp($x as node()*,$p as xs:string,$f as function) { >> $x/*[name(.) = $p][$f(.)] >> }; >> >> return collection("/db/titles")//root[local:and( >> local:comp(.,'type','Paperback',local:eq#2), >> local:or( >> local:comp(.,'date',empty#1), >> local:comp(.,'date','20130101',local:gt#2) >> ))] >> >> >> However, performance is even worse than util:eval. Is there any way to >> improve upon "util:eval with a concatenated xpath string", or are there >> other viable approaches closer to the one above? >> >> Thanks. >> >> PS. as you can see there's more to improve in the above, because the >> functions are still stated within square brackets to prevent forloops. >> >>  >> >> W.S. Hager >> Lagua Web Solutions >> http://lagua.nl >> >> >>  >> Learn the latestVisual Studio 2012, SharePoint 2013, SQL 2012, more! >> Discover the easy way to master current and previous Microsoft technologies >> and advance your career. Get an incredible 1,500+ hours of stepbystep >> tutorial videos with LearnDevNow. Subscribe today and save! >> http://pubads.g.doubleclick.net/gampad/clk?id=58040911&iu=/4140/ostg.clktrk >> _______________________________________________ >> Existopen mailing list >> Existopen@... >> https://lists.sourceforge.net/lists/listinfo/existopen >> > > > >  > Adam Retter > > eXist Developer > { United Kingdom } > adam@... > irc://irc.freenode.net/existdb  Adam Retter eXist Developer { United Kingdom } adam@... irc://irc.freenode.net/existdb 
From: Adam Retter <adam@ex...>  20130828 21:28:15

Of course, you can also do away with the need for $p at all, but somehow I feel that it may be a useful mental abstraction ;) On 28 August 2013 22:26, Adam Retter <adam@...> wrote: > I just realised that for an even more natural syntax, you could in > fact use declared variables assigned to anonymous instead of declared > functions for the logic, i.e.: > > declare variable $or := function($ctx as item()*, $left as > function(item()*) as xs:boolean*, $right as function(item()*) as > xs:boolean*) as xs:boolean { > $left($ctx) = true() or $right($ctx) = true() > }; > > declare variable $and := function($ctx as item()*, $left as > function(item()*) as xs:boolean*, $right as function(item()*) as > xs:boolean*) as xs:boolean { > $left($ctx) = true() and $right($ctx) = true() > }; > > declare variable $p := function($ctx as item()*, $fn as > function(item()*) as xs:boolean) as xs:boolean { > $fn($ctx) = true() > }; > > $list[$p(., > $and(?, > function($ctx) { $ctx/type = "Paperback" }, > $or(?, function($ctx) { $ctx/empty(date) }, > function($ctx) { $ctx/date > '20130101' }) > ) > )] > > > Cheers Adam. > > On 28 August 2013 22:21, Adam Retter <adam@...> wrote: >> I think I am correct in saying that the functional approach that you >> want to achieve is possible using currying. A predicate is basically >> an expression that evaluates to an `effective boolean value`, as such >> you can use any function that returns true() or false(). Such a >> function can be built dynamically by using partial function >> application (to achieve currying) and function passing. >> >> I have no idea of the performance profile of this approach, however I >> would guess that the optimiser could not yet do anything with this >> approach. But if your really careful, you might not need the optimiser >> anyway ;) I would love to hear Wolfgang's thoughts on this... >> >> I think the downside to the approach below, is that each thing in the >> context ($ctx) may need to be checked against your evaluation, whereas >> inside a predicate with the optimiser, I guess as soon as the first >> true result is found when working with a sequence it can stop >> evaluation. This may still hold, I am not so clear on some of the >> internals of eXist's optimisation strategy. >> >> Basically you can dynamically build your predicate like so  >> >> xquery version "3.0"; >> >> declare function local:and($ctx as item()*, $left as function(item()*) >> as xs:boolean*, $right as function(item()*) as xs:boolean*) as >> xs:boolean { >> $left($ctx) = true() and $right($ctx) = true() >> }; >> >> declare function local:or($ctx as item()*, $left as function(item()*) >> as xs:boolean*, $right as function(item()*) as xs:boolean*) as >> xs:boolean { >> $left($ctx) = true() or $right($ctx) = true() >> }; >> >> declare function local:predicate($ctx as item()*, $fn as >> function(item()*) as xs:boolean) as xs:boolean { >> $fn($ctx) = true() >> }; >> >> You could then apply your predicate using  >> >> $list[local:predicate(., >> local:and(?, >> function($ctx) { $ctx/type = "Paperback" }, >> local:or(?, function($ctx) { $ctx/empty(date) }, >> function($ctx) { $ctx/date > '20130101' }) >> ) >> )] >> >> The three anonymous inline functions above that are effectively your >> equality tests, could easily be generated by further function calls, I >> have simply inlined them to keep the example simple. >> >> For testing this, I used the following  >> >> let $data := ( >> <container> >> <type>Paperback</type> >> <date>20130102</date> >> </container>) return >> >> local:predicate( >> $data, >> local:and(?, >> function($ctx) { $ctx/type = "Paperback" }, >> local:or(?, function($ctx) { $ctx/empty(date) }, >> function($ctx) { $ctx/date > '20130101' }) >> ) >> ) >> >> >> You may also be interested in this  https://github.com/jpcs/functional.xq >> I would think that the curry and compose functions could prove useful to you. >> >> ...It's just "Turtles all the way down" ;) >> >> >> >> On 28 August 2013 15:17, W.S. Hager <wshager@...> wrote: >>> Hi, >>> >>> I've been looking at a way to make node selections based on xpath strings. >>> In other words, I want to translate arbitrary pieces of xpath into >>> higherorder functions. >>> >>> Please consider the example: >>> >>> $list[type eq 'Paperback' and (empty(date) or date > '20130101')] >>> >>> This is pretty straightforward in xpath. However, in my app I want to >>> reassemble the xpath expression from query parameters. I currently use >>> util:eval to evaluate the stuff between square brackets above. >>> >>> However, eval is evil and the performance is not good enough for more >>> complex expression. So I thought I'd try to compose the expression out of >>> higherorder functions. >>> >>> Please consider this xquery 3.0: >>> >>> declare function local:and($a, $b) { >>> $a and $b >>> }; >>> >>> declare function local:or($a, $b) { >>> $a or $b >>> }; >>> >>> declare function local:eq($p, $t) { >>> $p eq $t >>> }; >>> >>> declare function local:gt($p, $t) { >>> $p gt $t >>> }; >>> >>> declare function local:comp($x as node()*,$p as xs:string,$t as xs:string, >>> $f as function) { >>> $x/*[name(.) = $p][$f(.,$t)] >>> }; >>> >>> declare function local:comp($x as node()*,$p as xs:string,$f as function) { >>> $x/*[name(.) = $p][$f(.)] >>> }; >>> >>> return collection("/db/titles")//root[local:and( >>> local:comp(.,'type','Paperback',local:eq#2), >>> local:or( >>> local:comp(.,'date',empty#1), >>> local:comp(.,'date','20130101',local:gt#2) >>> ))] >>> >>> >>> However, performance is even worse than util:eval. Is there any way to >>> improve upon "util:eval with a concatenated xpath string", or are there >>> other viable approaches closer to the one above? >>> >>> Thanks. >>> >>> PS. as you can see there's more to improve in the above, because the >>> functions are still stated within square brackets to prevent forloops. >>> >>>  >>> >>> W.S. Hager >>> Lagua Web Solutions >>> http://lagua.nl >>> >>> >>>  >>> Learn the latestVisual Studio 2012, SharePoint 2013, SQL 2012, more! >>> Discover the easy way to master current and previous Microsoft technologies >>> and advance your career. Get an incredible 1,500+ hours of stepbystep >>> tutorial videos with LearnDevNow. Subscribe today and save! >>> http://pubads.g.doubleclick.net/gampad/clk?id=58040911&iu=/4140/ostg.clktrk >>> _______________________________________________ >>> Existopen mailing list >>> Existopen@... >>> https://lists.sourceforge.net/lists/listinfo/existopen >>> >> >> >> >>  >> Adam Retter >> >> eXist Developer >> { United Kingdom } >> adam@... >> irc://irc.freenode.net/existdb > > > >  > Adam Retter > > eXist Developer > { United Kingdom } > adam@... > irc://irc.freenode.net/existdb  Adam Retter eXist Developer { United Kingdom } adam@... irc://irc.freenode.net/existdb 
From: W.S. Hager <wshager@gm...>  20130829 08:57:06
Attachments:
Message as HTML

Hi Adam, Currying was indeed what I did to get anonymous expressions into square brackets. However, neither functions assigned to variables nor currying with ? yielded any results. Did you test those? Thanks. Wouter 2013/8/28 Adam Retter <adam@...> > I just realised that for an even more natural syntax, you could in > fact use declared variables assigned to anonymous instead of declared > functions for the logic, i.e.: > > declare variable $or := function($ctx as item()*, $left as > function(item()*) as xs:boolean*, $right as function(item()*) as > xs:boolean*) as xs:boolean { > $left($ctx) = true() or $right($ctx) = true() > }; > > declare variable $and := function($ctx as item()*, $left as > function(item()*) as xs:boolean*, $right as function(item()*) as > xs:boolean*) as xs:boolean { > $left($ctx) = true() and $right($ctx) = true() > }; > > declare variable $p := function($ctx as item()*, $fn as > function(item()*) as xs:boolean) as xs:boolean { > $fn($ctx) = true() > }; > > $list[$p(., > $and(?, > function($ctx) { $ctx/type = "Paperback" }, > $or(?, function($ctx) { $ctx/empty(date) }, > function($ctx) { $ctx/date > '20130101' }) > ) > )] > > > Cheers Adam. > > On 28 August 2013 22:21, Adam Retter <adam@...> wrote: > > I think I am correct in saying that the functional approach that you > > want to achieve is possible using currying. A predicate is basically > > an expression that evaluates to an `effective boolean value`, as such > > you can use any function that returns true() or false(). Such a > > function can be built dynamically by using partial function > > application (to achieve currying) and function passing. > > > > I have no idea of the performance profile of this approach, however I > > would guess that the optimiser could not yet do anything with this > > approach. But if your really careful, you might not need the optimiser > > anyway ;) I would love to hear Wolfgang's thoughts on this... > > > > I think the downside to the approach below, is that each thing in the > > context ($ctx) may need to be checked against your evaluation, whereas > > inside a predicate with the optimiser, I guess as soon as the first > > true result is found when working with a sequence it can stop > > evaluation. This may still hold, I am not so clear on some of the > > internals of eXist's optimisation strategy. > > > > Basically you can dynamically build your predicate like so  > > > > xquery version "3.0"; > > > > declare function local:and($ctx as item()*, $left as function(item()*) > > as xs:boolean*, $right as function(item()*) as xs:boolean*) as > > xs:boolean { > > $left($ctx) = true() and $right($ctx) = true() > > }; > > > > declare function local:or($ctx as item()*, $left as function(item()*) > > as xs:boolean*, $right as function(item()*) as xs:boolean*) as > > xs:boolean { > > $left($ctx) = true() or $right($ctx) = true() > > }; > > > > declare function local:predicate($ctx as item()*, $fn as > > function(item()*) as xs:boolean) as xs:boolean { > > $fn($ctx) = true() > > }; > > > > You could then apply your predicate using  > > > > $list[local:predicate(., > > local:and(?, > > function($ctx) { $ctx/type = "Paperback" }, > > local:or(?, function($ctx) { $ctx/empty(date) }, > > function($ctx) { $ctx/date > '20130101' }) > > ) > > )] > > > > The three anonymous inline functions above that are effectively your > > equality tests, could easily be generated by further function calls, I > > have simply inlined them to keep the example simple. > > > > For testing this, I used the following  > > > > let $data := ( > > <container> > > <type>Paperback</type> > > <date>20130102</date> > > </container>) return > > > > local:predicate( > > $data, > > local:and(?, > > function($ctx) { $ctx/type = "Paperback" }, > > local:or(?, function($ctx) { $ctx/empty(date) }, > > function($ctx) { $ctx/date > '20130101' }) > > ) > > ) > > > > > > You may also be interested in this  > https://github.com/jpcs/functional.xq > > I would think that the curry and compose functions could prove useful to > you. > > > > ...It's just "Turtles all the way down" ;) > > > > > > > > On 28 August 2013 15:17, W.S. Hager <wshager@...> wrote: > >> Hi, > >> > >> I've been looking at a way to make node selections based on xpath > strings. > >> In other words, I want to translate arbitrary pieces of xpath into > >> higherorder functions. > >> > >> Please consider the example: > >> > >> $list[type eq 'Paperback' and (empty(date) or date > '20130101')] > >> > >> This is pretty straightforward in xpath. However, in my app I want to > >> reassemble the xpath expression from query parameters. I currently use > >> util:eval to evaluate the stuff between square brackets above. > >> > >> However, eval is evil and the performance is not good enough for more > >> complex expression. So I thought I'd try to compose the expression out > of > >> higherorder functions. > >> > >> Please consider this xquery 3.0: > >> > >> declare function local:and($a, $b) { > >> $a and $b > >> }; > >> > >> declare function local:or($a, $b) { > >> $a or $b > >> }; > >> > >> declare function local:eq($p, $t) { > >> $p eq $t > >> }; > >> > >> declare function local:gt($p, $t) { > >> $p gt $t > >> }; > >> > >> declare function local:comp($x as node()*,$p as xs:string,$t as > xs:string, > >> $f as function) { > >> $x/*[name(.) = $p][$f(.,$t)] > >> }; > >> > >> declare function local:comp($x as node()*,$p as xs:string,$f as > function) { > >> $x/*[name(.) = $p][$f(.)] > >> }; > >> > >> return collection("/db/titles")//root[local:and( > >> local:comp(.,'type','Paperback',local:eq#2), > >> local:or( > >> local:comp(.,'date',empty#1), > >> local:comp(.,'date','20130101',local:gt#2) > >> ))] > >> > >> > >> However, performance is even worse than util:eval. Is there any way to > >> improve upon "util:eval with a concatenated xpath string", or are there > >> other viable approaches closer to the one above? > >> > >> Thanks. > >> > >> PS. as you can see there's more to improve in the above, because the > >> functions are still stated within square brackets to prevent forloops. > >> > >>  > >> > >> W.S. Hager > >> Lagua Web Solutions > >> http://lagua.nl > >> > >> > >> >  > >> Learn the latestVisual Studio 2012, SharePoint 2013, SQL 2012, more! > >> Discover the easy way to master current and previous Microsoft > technologies > >> and advance your career. Get an incredible 1,500+ hours of stepbystep > >> tutorial videos with LearnDevNow. Subscribe today and save! > >> > http://pubads.g.doubleclick.net/gampad/clk?id=58040911&iu=/4140/ostg.clktrk > >> _______________________________________________ > >> Existopen mailing list > >> Existopen@... > >> https://lists.sourceforge.net/lists/listinfo/existopen > >> > > > > > > > >  > > Adam Retter > > > > eXist Developer > > { United Kingdom } > > adam@... > > irc://irc.freenode.net/existdb > > > >  > Adam Retter > > eXist Developer > { United Kingdom } > adam@... > irc://irc.freenode.net/existdb >  W.S. Hager Lagua Web Solutions http://lagua.nl 
From: Adam Retter <adam@ex...>  20130829 09:10:11

Yes the test I mentioned was done using Saxon as I was away from my Laptop and did not have a copy of eXist handy. If it works in Saxon it *should* work in eXist, if not it is most likely a bug  let us know... On 29 August 2013 09:56, W.S. Hager <wshager@...> wrote: > Hi Adam, > > Currying was indeed what I did to get anonymous expressions into square > brackets. However, neither functions assigned to variables nor currying with > ? yielded any results. Did you test those? > > Thanks. > > Wouter > > > 2013/8/28 Adam Retter <adam@...> >> >> I just realised that for an even more natural syntax, you could in >> fact use declared variables assigned to anonymous instead of declared >> functions for the logic, i.e.: >> >> declare variable $or := function($ctx as item()*, $left as >> function(item()*) as xs:boolean*, $right as function(item()*) as >> xs:boolean*) as xs:boolean { >> $left($ctx) = true() or $right($ctx) = true() >> }; >> >> declare variable $and := function($ctx as item()*, $left as >> function(item()*) as xs:boolean*, $right as function(item()*) as >> xs:boolean*) as xs:boolean { >> $left($ctx) = true() and $right($ctx) = true() >> }; >> >> declare variable $p := function($ctx as item()*, $fn as >> function(item()*) as xs:boolean) as xs:boolean { >> $fn($ctx) = true() >> }; >> >> $list[$p(., >> $and(?, >> function($ctx) { $ctx/type = "Paperback" }, >> $or(?, function($ctx) { $ctx/empty(date) }, >> function($ctx) { $ctx/date > '20130101' }) >> ) >> )] >> >> >> Cheers Adam. >> >> On 28 August 2013 22:21, Adam Retter <adam@...> wrote: >> > I think I am correct in saying that the functional approach that you >> > want to achieve is possible using currying. A predicate is basically >> > an expression that evaluates to an `effective boolean value`, as such >> > you can use any function that returns true() or false(). Such a >> > function can be built dynamically by using partial function >> > application (to achieve currying) and function passing. >> > >> > I have no idea of the performance profile of this approach, however I >> > would guess that the optimiser could not yet do anything with this >> > approach. But if your really careful, you might not need the optimiser >> > anyway ;) I would love to hear Wolfgang's thoughts on this... >> > >> > I think the downside to the approach below, is that each thing in the >> > context ($ctx) may need to be checked against your evaluation, whereas >> > inside a predicate with the optimiser, I guess as soon as the first >> > true result is found when working with a sequence it can stop >> > evaluation. This may still hold, I am not so clear on some of the >> > internals of eXist's optimisation strategy. >> > >> > Basically you can dynamically build your predicate like so  >> > >> > xquery version "3.0"; >> > >> > declare function local:and($ctx as item()*, $left as function(item()*) >> > as xs:boolean*, $right as function(item()*) as xs:boolean*) as >> > xs:boolean { >> > $left($ctx) = true() and $right($ctx) = true() >> > }; >> > >> > declare function local:or($ctx as item()*, $left as function(item()*) >> > as xs:boolean*, $right as function(item()*) as xs:boolean*) as >> > xs:boolean { >> > $left($ctx) = true() or $right($ctx) = true() >> > }; >> > >> > declare function local:predicate($ctx as item()*, $fn as >> > function(item()*) as xs:boolean) as xs:boolean { >> > $fn($ctx) = true() >> > }; >> > >> > You could then apply your predicate using  >> > >> > $list[local:predicate(., >> > local:and(?, >> > function($ctx) { $ctx/type = "Paperback" }, >> > local:or(?, function($ctx) { $ctx/empty(date) }, >> > function($ctx) { $ctx/date > '20130101' }) >> > ) >> > )] >> > >> > The three anonymous inline functions above that are effectively your >> > equality tests, could easily be generated by further function calls, I >> > have simply inlined them to keep the example simple. >> > >> > For testing this, I used the following  >> > >> > let $data := ( >> > <container> >> > <type>Paperback</type> >> > <date>20130102</date> >> > </container>) return >> > >> > local:predicate( >> > $data, >> > local:and(?, >> > function($ctx) { $ctx/type = "Paperback" }, >> > local:or(?, function($ctx) { $ctx/empty(date) }, >> > function($ctx) { $ctx/date > '20130101' }) >> > ) >> > ) >> > >> > >> > You may also be interested in this  >> > https://github.com/jpcs/functional.xq >> > I would think that the curry and compose functions could prove useful to >> > you. >> > >> > ...It's just "Turtles all the way down" ;) >> > >> > >> > >> > On 28 August 2013 15:17, W.S. Hager <wshager@...> wrote: >> >> Hi, >> >> >> >> I've been looking at a way to make node selections based on xpath >> >> strings. >> >> In other words, I want to translate arbitrary pieces of xpath into >> >> higherorder functions. >> >> >> >> Please consider the example: >> >> >> >> $list[type eq 'Paperback' and (empty(date) or date > '20130101')] >> >> >> >> This is pretty straightforward in xpath. However, in my app I want to >> >> reassemble the xpath expression from query parameters. I currently use >> >> util:eval to evaluate the stuff between square brackets above. >> >> >> >> However, eval is evil and the performance is not good enough for more >> >> complex expression. So I thought I'd try to compose the expression out >> >> of >> >> higherorder functions. >> >> >> >> Please consider this xquery 3.0: >> >> >> >> declare function local:and($a, $b) { >> >> $a and $b >> >> }; >> >> >> >> declare function local:or($a, $b) { >> >> $a or $b >> >> }; >> >> >> >> declare function local:eq($p, $t) { >> >> $p eq $t >> >> }; >> >> >> >> declare function local:gt($p, $t) { >> >> $p gt $t >> >> }; >> >> >> >> declare function local:comp($x as node()*,$p as xs:string,$t as >> >> xs:string, >> >> $f as function) { >> >> $x/*[name(.) = $p][$f(.,$t)] >> >> }; >> >> >> >> declare function local:comp($x as node()*,$p as xs:string,$f as >> >> function) { >> >> $x/*[name(.) = $p][$f(.)] >> >> }; >> >> >> >> return collection("/db/titles")//root[local:and( >> >> local:comp(.,'type','Paperback',local:eq#2), >> >> local:or( >> >> local:comp(.,'date',empty#1), >> >> local:comp(.,'date','20130101',local:gt#2) >> >> ))] >> >> >> >> >> >> However, performance is even worse than util:eval. Is there any way to >> >> improve upon "util:eval with a concatenated xpath string", or are there >> >> other viable approaches closer to the one above? >> >> >> >> Thanks. >> >> >> >> PS. as you can see there's more to improve in the above, because the >> >> functions are still stated within square brackets to prevent forloops. >> >> >> >>  >> >> >> >> W.S. Hager >> >> Lagua Web Solutions >> >> http://lagua.nl >> >> >> >> >> >> >> >>  >> >> Learn the latestVisual Studio 2012, SharePoint 2013, SQL 2012, more! >> >> Discover the easy way to master current and previous Microsoft >> >> technologies >> >> and advance your career. Get an incredible 1,500+ hours of stepbystep >> >> tutorial videos with LearnDevNow. Subscribe today and save! >> >> >> >> http://pubads.g.doubleclick.net/gampad/clk?id=58040911&iu=/4140/ostg.clktrk >> >> _______________________________________________ >> >> Existopen mailing list >> >> Existopen@... >> >> https://lists.sourceforge.net/lists/listinfo/existopen >> >> >> > >> > >> > >> >  >> > Adam Retter >> > >> > eXist Developer >> > { United Kingdom } >> > adam@... >> > irc://irc.freenode.net/existdb >> >> >> >>  >> Adam Retter >> >> eXist Developer >> { United Kingdom } >> adam@... >> irc://irc.freenode.net/existdb > > > > >  > > W.S. Hager > Lagua Web Solutions > http://lagua.nl  Adam Retter eXist Developer { United Kingdom } adam@... irc://irc.freenode.net/existdb 
From: W.S. Hager <wshager@gm...>  20130829 09:34:38
Attachments:
Message as HTML

Then there is a bug in eXist: I can't pass functions as arguments to curry. Execution also stops upon encountering the currying with function arg. Simple test: xquery version "3.0"; declare variable $a := function($x as item()*, $f as function(item()*) as xs:boolean) as xs:boolean { $f($x) }; let $list := ( <test/> ) let $f := $a(?,function($x){ true() }) return $f($list) 2013/8/29 Adam Retter <adam@...> > Yes the test I mentioned was done using Saxon as I was away from my > Laptop and did not have a copy of eXist handy. If it works in Saxon it > *should* work in eXist, if not it is most likely a bug  let us > know... > > On 29 August 2013 09:56, W.S. Hager <wshager@...> wrote: > > Hi Adam, > > > > Currying was indeed what I did to get anonymous expressions into square > > brackets. However, neither functions assigned to variables nor currying > with > > ? yielded any results. Did you test those? > > > > Thanks. > > > > Wouter > > > > > > 2013/8/28 Adam Retter <adam@...> > >> > >> I just realised that for an even more natural syntax, you could in > >> fact use declared variables assigned to anonymous instead of declared > >> functions for the logic, i.e.: > >> > >> declare variable $or := function($ctx as item()*, $left as > >> function(item()*) as xs:boolean*, $right as function(item()*) as > >> xs:boolean*) as xs:boolean { > >> $left($ctx) = true() or $right($ctx) = true() > >> }; > >> > >> declare variable $and := function($ctx as item()*, $left as > >> function(item()*) as xs:boolean*, $right as function(item()*) as > >> xs:boolean*) as xs:boolean { > >> $left($ctx) = true() and $right($ctx) = true() > >> }; > >> > >> declare variable $p := function($ctx as item()*, $fn as > >> function(item()*) as xs:boolean) as xs:boolean { > >> $fn($ctx) = true() > >> }; > >> > >> $list[$p(., > >> $and(?, > >> function($ctx) { $ctx/type = "Paperback" }, > >> $or(?, function($ctx) { $ctx/empty(date) }, > >> function($ctx) { $ctx/date > '20130101' }) > >> ) > >> )] > >> > >> > >> Cheers Adam. > >> > >> On 28 August 2013 22:21, Adam Retter <adam@...> wrote: > >> > I think I am correct in saying that the functional approach that you > >> > want to achieve is possible using currying. A predicate is basically > >> > an expression that evaluates to an `effective boolean value`, as such > >> > you can use any function that returns true() or false(). Such a > >> > function can be built dynamically by using partial function > >> > application (to achieve currying) and function passing. > >> > > >> > I have no idea of the performance profile of this approach, however I > >> > would guess that the optimiser could not yet do anything with this > >> > approach. But if your really careful, you might not need the optimiser > >> > anyway ;) I would love to hear Wolfgang's thoughts on this... > >> > > >> > I think the downside to the approach below, is that each thing in the > >> > context ($ctx) may need to be checked against your evaluation, whereas > >> > inside a predicate with the optimiser, I guess as soon as the first > >> > true result is found when working with a sequence it can stop > >> > evaluation. This may still hold, I am not so clear on some of the > >> > internals of eXist's optimisation strategy. > >> > > >> > Basically you can dynamically build your predicate like so  > >> > > >> > xquery version "3.0"; > >> > > >> > declare function local:and($ctx as item()*, $left as function(item()*) > >> > as xs:boolean*, $right as function(item()*) as xs:boolean*) as > >> > xs:boolean { > >> > $left($ctx) = true() and $right($ctx) = true() > >> > }; > >> > > >> > declare function local:or($ctx as item()*, $left as function(item()*) > >> > as xs:boolean*, $right as function(item()*) as xs:boolean*) as > >> > xs:boolean { > >> > $left($ctx) = true() or $right($ctx) = true() > >> > }; > >> > > >> > declare function local:predicate($ctx as item()*, $fn as > >> > function(item()*) as xs:boolean) as xs:boolean { > >> > $fn($ctx) = true() > >> > }; > >> > > >> > You could then apply your predicate using  > >> > > >> > $list[local:predicate(., > >> > local:and(?, > >> > function($ctx) { $ctx/type = "Paperback" }, > >> > local:or(?, function($ctx) { $ctx/empty(date) }, > >> > function($ctx) { $ctx/date > '20130101' }) > >> > ) > >> > )] > >> > > >> > The three anonymous inline functions above that are effectively your > >> > equality tests, could easily be generated by further function calls, I > >> > have simply inlined them to keep the example simple. > >> > > >> > For testing this, I used the following  > >> > > >> > let $data := ( > >> > <container> > >> > <type>Paperback</type> > >> > <date>20130102</date> > >> > </container>) return > >> > > >> > local:predicate( > >> > $data, > >> > local:and(?, > >> > function($ctx) { $ctx/type = "Paperback" }, > >> > local:or(?, function($ctx) { $ctx/empty(date) }, > >> > function($ctx) { $ctx/date > '20130101' }) > >> > ) > >> > ) > >> > > >> > > >> > You may also be interested in this  > >> > https://github.com/jpcs/functional.xq > >> > I would think that the curry and compose functions could prove useful > to > >> > you. > >> > > >> > ...It's just "Turtles all the way down" ;) > >> > > >> > > >> > > >> > On 28 August 2013 15:17, W.S. Hager <wshager@...> wrote: > >> >> Hi, > >> >> > >> >> I've been looking at a way to make node selections based on xpath > >> >> strings. > >> >> In other words, I want to translate arbitrary pieces of xpath into > >> >> higherorder functions. > >> >> > >> >> Please consider the example: > >> >> > >> >> $list[type eq 'Paperback' and (empty(date) or date > '20130101')] > >> >> > >> >> This is pretty straightforward in xpath. However, in my app I want to > >> >> reassemble the xpath expression from query parameters. I currently > use > >> >> util:eval to evaluate the stuff between square brackets above. > >> >> > >> >> However, eval is evil and the performance is not good enough for more > >> >> complex expression. So I thought I'd try to compose the expression > out > >> >> of > >> >> higherorder functions. > >> >> > >> >> Please consider this xquery 3.0: > >> >> > >> >> declare function local:and($a, $b) { > >> >> $a and $b > >> >> }; > >> >> > >> >> declare function local:or($a, $b) { > >> >> $a or $b > >> >> }; > >> >> > >> >> declare function local:eq($p, $t) { > >> >> $p eq $t > >> >> }; > >> >> > >> >> declare function local:gt($p, $t) { > >> >> $p gt $t > >> >> }; > >> >> > >> >> declare function local:comp($x as node()*,$p as xs:string,$t as > >> >> xs:string, > >> >> $f as function) { > >> >> $x/*[name(.) = $p][$f(.,$t)] > >> >> }; > >> >> > >> >> declare function local:comp($x as node()*,$p as xs:string,$f as > >> >> function) { > >> >> $x/*[name(.) = $p][$f(.)] > >> >> }; > >> >> > >> >> return collection("/db/titles")//root[local:and( > >> >> local:comp(.,'type','Paperback',local:eq#2), > >> >> local:or( > >> >> local:comp(.,'date',empty#1), > >> >> local:comp(.,'date','20130101',local:gt#2) > >> >> ))] > >> >> > >> >> > >> >> However, performance is even worse than util:eval. Is there any way > to > >> >> improve upon "util:eval with a concatenated xpath string", or are > there > >> >> other viable approaches closer to the one above? > >> >> > >> >> Thanks. > >> >> > >> >> PS. as you can see there's more to improve in the above, because the > >> >> functions are still stated within square brackets to prevent > forloops. > >> >> > >> >>  > >> >> > >> >> W.S. Hager > >> >> Lagua Web Solutions > >> >> http://lagua.nl > >> >> > >> >> > >> >> > >> >> >  > >> >> Learn the latestVisual Studio 2012, SharePoint 2013, SQL 2012, > more! > >> >> Discover the easy way to master current and previous Microsoft > >> >> technologies > >> >> and advance your career. Get an incredible 1,500+ hours of > stepbystep > >> >> tutorial videos with LearnDevNow. Subscribe today and save! > >> >> > >> >> > http://pubads.g.doubleclick.net/gampad/clk?id=58040911&iu=/4140/ostg.clktrk > >> >> _______________________________________________ > >> >> Existopen mailing list > >> >> Existopen@... > >> >> https://lists.sourceforge.net/lists/listinfo/existopen > >> >> > >> > > >> > > >> > > >> >  > >> > Adam Retter > >> > > >> > eXist Developer > >> > { United Kingdom } > >> > adam@... > >> > irc://irc.freenode.net/existdb > >> > >> > >> > >>  > >> Adam Retter > >> > >> eXist Developer > >> { United Kingdom } > >> adam@... > >> irc://irc.freenode.net/existdb > > > > > > > > > >  > > > > W.S. Hager > > Lagua Web Solutions > > http://lagua.nl > > > >  > Adam Retter > > eXist Developer > { United Kingdom } > adam@... > irc://irc.freenode.net/existdb >  W.S. Hager Lagua Web Solutions http://lagua.nl 
From: W.S. Hager <wshager@gm...>  20130829 09:56:29
Attachments:
Message as HTML

This seems limited to anonymous functions. I can do this: xquery version "3.0"; let $a := function($x as item()*, $f as function) as xs:boolean { $f($x) } let $b := function($x as item()*) as xs:boolean { true() } let $list := ( <test/> ) let $f := $a(?,$b) return $f($list) 2013/8/29 W.S. Hager <wshager@...> > Then there is a bug in eXist: I can't pass functions as arguments to > curry. Execution also stops upon encountering the currying with function > arg. Simple test: > > xquery version "3.0"; > > declare variable $a := function($x as item()*, $f as function(item()*) as > xs:boolean) as xs:boolean { > $f($x) > }; > > let $list := ( > <test/> > ) > > let $f := $a(?,function($x){ true() }) > > return $f($list) > > > 2013/8/29 Adam Retter <adam@...> > >> Yes the test I mentioned was done using Saxon as I was away from my >> Laptop and did not have a copy of eXist handy. If it works in Saxon it >> *should* work in eXist, if not it is most likely a bug  let us >> know... >> >> On 29 August 2013 09:56, W.S. Hager <wshager@...> wrote: >> > Hi Adam, >> > >> > Currying was indeed what I did to get anonymous expressions into square >> > brackets. However, neither functions assigned to variables nor currying >> with >> > ? yielded any results. Did you test those? >> > >> > Thanks. >> > >> > Wouter >> > >> > >> > 2013/8/28 Adam Retter <adam@...> >> >> >> >> I just realised that for an even more natural syntax, you could in >> >> fact use declared variables assigned to anonymous instead of declared >> >> functions for the logic, i.e.: >> >> >> >> declare variable $or := function($ctx as item()*, $left as >> >> function(item()*) as xs:boolean*, $right as function(item()*) as >> >> xs:boolean*) as xs:boolean { >> >> $left($ctx) = true() or $right($ctx) = true() >> >> }; >> >> >> >> declare variable $and := function($ctx as item()*, $left as >> >> function(item()*) as xs:boolean*, $right as function(item()*) as >> >> xs:boolean*) as xs:boolean { >> >> $left($ctx) = true() and $right($ctx) = true() >> >> }; >> >> >> >> declare variable $p := function($ctx as item()*, $fn as >> >> function(item()*) as xs:boolean) as xs:boolean { >> >> $fn($ctx) = true() >> >> }; >> >> >> >> $list[$p(., >> >> $and(?, >> >> function($ctx) { $ctx/type = "Paperback" }, >> >> $or(?, function($ctx) { $ctx/empty(date) }, >> >> function($ctx) { $ctx/date > '20130101' }) >> >> ) >> >> )] >> >> >> >> >> >> Cheers Adam. >> >> >> >> On 28 August 2013 22:21, Adam Retter <adam@...> wrote: >> >> > I think I am correct in saying that the functional approach that you >> >> > want to achieve is possible using currying. A predicate is basically >> >> > an expression that evaluates to an `effective boolean value`, as such >> >> > you can use any function that returns true() or false(). Such a >> >> > function can be built dynamically by using partial function >> >> > application (to achieve currying) and function passing. >> >> > >> >> > I have no idea of the performance profile of this approach, however I >> >> > would guess that the optimiser could not yet do anything with this >> >> > approach. But if your really careful, you might not need the >> optimiser >> >> > anyway ;) I would love to hear Wolfgang's thoughts on this... >> >> > >> >> > I think the downside to the approach below, is that each thing in the >> >> > context ($ctx) may need to be checked against your evaluation, >> whereas >> >> > inside a predicate with the optimiser, I guess as soon as the first >> >> > true result is found when working with a sequence it can stop >> >> > evaluation. This may still hold, I am not so clear on some of the >> >> > internals of eXist's optimisation strategy. >> >> > >> >> > Basically you can dynamically build your predicate like so  >> >> > >> >> > xquery version "3.0"; >> >> > >> >> > declare function local:and($ctx as item()*, $left as >> function(item()*) >> >> > as xs:boolean*, $right as function(item()*) as xs:boolean*) as >> >> > xs:boolean { >> >> > $left($ctx) = true() and $right($ctx) = true() >> >> > }; >> >> > >> >> > declare function local:or($ctx as item()*, $left as function(item()*) >> >> > as xs:boolean*, $right as function(item()*) as xs:boolean*) as >> >> > xs:boolean { >> >> > $left($ctx) = true() or $right($ctx) = true() >> >> > }; >> >> > >> >> > declare function local:predicate($ctx as item()*, $fn as >> >> > function(item()*) as xs:boolean) as xs:boolean { >> >> > $fn($ctx) = true() >> >> > }; >> >> > >> >> > You could then apply your predicate using  >> >> > >> >> > $list[local:predicate(., >> >> > local:and(?, >> >> > function($ctx) { $ctx/type = "Paperback" }, >> >> > local:or(?, function($ctx) { $ctx/empty(date) }, >> >> > function($ctx) { $ctx/date > '20130101' }) >> >> > ) >> >> > )] >> >> > >> >> > The three anonymous inline functions above that are effectively your >> >> > equality tests, could easily be generated by further function calls, >> I >> >> > have simply inlined them to keep the example simple. >> >> > >> >> > For testing this, I used the following  >> >> > >> >> > let $data := ( >> >> > <container> >> >> > <type>Paperback</type> >> >> > <date>20130102</date> >> >> > </container>) return >> >> > >> >> > local:predicate( >> >> > $data, >> >> > local:and(?, >> >> > function($ctx) { $ctx/type = "Paperback" }, >> >> > local:or(?, function($ctx) { $ctx/empty(date) }, >> >> > function($ctx) { $ctx/date > '20130101' }) >> >> > ) >> >> > ) >> >> > >> >> > >> >> > You may also be interested in this  >> >> > https://github.com/jpcs/functional.xq >> >> > I would think that the curry and compose functions could prove >> useful to >> >> > you. >> >> > >> >> > ...It's just "Turtles all the way down" ;) >> >> > >> >> > >> >> > >> >> > On 28 August 2013 15:17, W.S. Hager <wshager@...> wrote: >> >> >> Hi, >> >> >> >> >> >> I've been looking at a way to make node selections based on xpath >> >> >> strings. >> >> >> In other words, I want to translate arbitrary pieces of xpath into >> >> >> higherorder functions. >> >> >> >> >> >> Please consider the example: >> >> >> >> >> >> $list[type eq 'Paperback' and (empty(date) or date > '20130101')] >> >> >> >> >> >> This is pretty straightforward in xpath. However, in my app I want >> to >> >> >> reassemble the xpath expression from query parameters. I currently >> use >> >> >> util:eval to evaluate the stuff between square brackets above. >> >> >> >> >> >> However, eval is evil and the performance is not good enough for >> more >> >> >> complex expression. So I thought I'd try to compose the expression >> out >> >> >> of >> >> >> higherorder functions. >> >> >> >> >> >> Please consider this xquery 3.0: >> >> >> >> >> >> declare function local:and($a, $b) { >> >> >> $a and $b >> >> >> }; >> >> >> >> >> >> declare function local:or($a, $b) { >> >> >> $a or $b >> >> >> }; >> >> >> >> >> >> declare function local:eq($p, $t) { >> >> >> $p eq $t >> >> >> }; >> >> >> >> >> >> declare function local:gt($p, $t) { >> >> >> $p gt $t >> >> >> }; >> >> >> >> >> >> declare function local:comp($x as node()*,$p as xs:string,$t as >> >> >> xs:string, >> >> >> $f as function) { >> >> >> $x/*[name(.) = $p][$f(.,$t)] >> >> >> }; >> >> >> >> >> >> declare function local:comp($x as node()*,$p as xs:string,$f as >> >> >> function) { >> >> >> $x/*[name(.) = $p][$f(.)] >> >> >> }; >> >> >> >> >> >> return collection("/db/titles")//root[local:and( >> >> >> local:comp(.,'type','Paperback',local:eq#2), >> >> >> local:or( >> >> >> local:comp(.,'date',empty#1), >> >> >> local:comp(.,'date','20130101',local:gt#2) >> >> >> ))] >> >> >> >> >> >> >> >> >> However, performance is even worse than util:eval. Is there any way >> to >> >> >> improve upon "util:eval with a concatenated xpath string", or are >> there >> >> >> other viable approaches closer to the one above? >> >> >> >> >> >> Thanks. >> >> >> >> >> >> PS. as you can see there's more to improve in the above, because the >> >> >> functions are still stated within square brackets to prevent >> forloops. >> >> >> >> >> >>  >> >> >> >> >> >> W.S. Hager >> >> >> Lagua Web Solutions >> >> >> http://lagua.nl >> >> >> >> >> >> >> >> >> >> >> >> >>  >> >> >> Learn the latestVisual Studio 2012, SharePoint 2013, SQL 2012, >> more! >> >> >> Discover the easy way to master current and previous Microsoft >> >> >> technologies >> >> >> and advance your career. Get an incredible 1,500+ hours of >> stepbystep >> >> >> tutorial videos with LearnDevNow. Subscribe today and save! >> >> >> >> >> >> >> http://pubads.g.doubleclick.net/gampad/clk?id=58040911&iu=/4140/ostg.clktrk >> >> >> _______________________________________________ >> >> >> Existopen mailing list >> >> >> Existopen@... >> >> >> https://lists.sourceforge.net/lists/listinfo/existopen >> >> >> >> >> > >> >> > >> >> > >> >> >  >> >> > Adam Retter >> >> > >> >> > eXist Developer >> >> > { United Kingdom } >> >> > adam@... >> >> > irc://irc.freenode.net/existdb >> >> >> >> >> >> >> >>  >> >> Adam Retter >> >> >> >> eXist Developer >> >> { United Kingdom } >> >> adam@... >> >> irc://irc.freenode.net/existdb >> > >> > >> > >> > >> >  >> > >> > W.S. Hager >> > Lagua Web Solutions >> > http://lagua.nl >> >> >> >>  >> Adam Retter >> >> eXist Developer >> { United Kingdom } >> adam@... >> irc://irc.freenode.net/existdb >> > > > >  > > W.S. Hager > Lagua Web Solutions > http://lagua.nl >  W.S. Hager Lagua Web Solutions http://lagua.nl 
From: <wolfgang@ex...>  20130829 14:30:21

> Then there is a bug in eXist: I can't pass functions as arguments to curry. > Execution also stops upon encountering the currying with function arg. There was a NullPointerException in the logs. I quickly fixed it: https://github.com/eXistdb/exist/pull/31 Wolfgang 
Sign up for the SourceForge newsletter:
No, thanks