XQuery question
Monday, 20 May 2013 · 5 messages
ML
Marco Lettere20 May 2013 14:51 #
Hello all,
sorry this email is not properly basex specific but rather XQuery related. What is the most correct, most efficient in general best way of treating sequences sequentially?
In particular I have an XML describing a sequence of set operations that have to be applied sequentially to the contained sequences of <tem/>s resulting into a final set represented by a sequence of <item/>s. Unfortunately they are expressed as siblings (flat) rather than dependent nodes (nested hierarchy) which could be handled easily with recursion.
As an example the following sequence shall add the first three items to the empty set then cut down the resulting set to only contain item 2 and 3 and finally remove item 2 from the set resulting in a final set containing only item 3.
<set operator="UNION">
<item name="1"/>
<item name="2"/>
<item name="3"/>
</set>
<set operator="INTERSECT">
<item name="2"/>
<item name="3"/>
<item name="4"/>
<item name="5"/>
</set>
<set operator="DIFFERENCE">
<item name="2"/>
</set>I'd prefer to not have to alter the input data structure.
Thanks a lot for any help,
M.
JE
Jens Erat20 May 2013 15:44 #
hi Marco,
using recursion is easily possible (and the only way to solve that problem without using maps), just write a small XQuery function like
declare function local:interprete($operations as item()*, $set as item()*) as item()* {
let $op := head($operations)
let $ops := tail($operations)
let $intermediate :=
switch($op/@operator)
case "UNION" return ($set, $op/item[not(@name = $set/@name)])
case "INTERSECT" return $set[@name = $op/item/@name]
case "DIFFERENCE" return $set[not(@name = $op/item/@name)]
default return error()
return
if ($ops)
then
local:interprete($ops, $intermediate)
else $intermediate
};Which you would call using
local:interpret(//set, ()). I guess the code should be small enough to be self-explaining. I seems to work, but I didn't test with much more than the input you provided, better do some additional tests on production data before using it.
If you want to compare whole nodes instead of their name attribute, use fn:deep-equal() instead of the name comparisons. You will have to use some explicit loop, [quantified expressions] should get handy for that.
Regards from Lake Constance, Germany,
Jens Erat
[quantified expressions]: http://www.w3.org/TR/xpath20/#id-quantified-expressions--
Jens Erat
[phone]: tel:+49-151-56961126
[mail]: mailto:email at jenserat.de
[jabber]: xmpp:jabber at jenserat.de
[web]: http://www.jenserat.de
PGP: 350E D9B6 9ADC 2DED F5F2 8549 CBC2 613C D745 722B
Quoted text · Marco Lettere · 30 lines
Am 20.05.2013 um 14:51 schrieb Marco Lettere <m.lettere at websynapsis.com>: > Hello all, > sorry this email is not properly basex specific but rather XQuery related. > What is the most correct, most efficient in general best way of treating sequences sequentially? > In particular I have an XML describing a sequence of set operations that have to be applied sequentially to the contained sequences of <tem/>s resulting into a final set represented by a sequence of <item/>s. > Unfortunately they are expressed as siblings (flat) rather than dependent nodes (nested hierarchy) which could be handled easily with recursion. > As an example the following sequence shall add the first three items to the empty set then cut down the resulting set to only contain item 2 and 3 and finally remove item 2 from the set resulting in a final set containing only item 3. > > <set operator="UNION"> > <item name="1"/> > <item name="2"/> > <item name="3"/> > </set> > <set operator="INTERSECT"> > <item name="2"/> > <item name="3"/> > <item name="4"/> > <item name="5"/> > </set> > <set operator="DIFFERENCE"> > <item name="2"/> > </set> > > I'd prefer to not have to alter the input data structure. > Thanks a lot for any help, > M. > _______________________________________________ > BaseX-Talk mailing list > BaseX-Talk at mailman.uni-konstanz.de > https://mailman.uni-konstanz.de/mailman/listinfo/basex-talk
ML
Marco Lettere20 May 2013 16:31 #
Thanks a lot.
I'm really wondering how I was able to overlook "head" and "tail" .... maybe the age .... :-(
M.
Quoted text · Jens Erat · 30 lines
On 05/20/2013 03:44 PM, Jens Erat wrote: > hi Marco, > > using recursion is easily possible (and the only way to solve that problem without using maps), just write a small XQuery function like > > declare function local:interprete($operations as item()*, $set as item()*) as item()* { > let $op := head($operations) > let $ops := tail($operations) > let $intermediate := > switch($op/@operator) > case "UNION" return ($set, $op/item[not(@name = $set/@name)]) > case "INTERSECT" return $set[@name = $op/item/@name] > case "DIFFERENCE" return $set[not(@name = $op/item/@name)] > default return error() > return > if ($ops) > then > local:interprete($ops, $intermediate) > else $intermediate > }; > > Which you would call using `local:interpret(//set, ())`. I guess the code should be small enough to be self-explaining. I seems to work, but I didn't test with much more than the input you provided, better do some additional tests on production data before using it. > > If you want to compare whole nodes instead of their name attribute, use `fn:deep-equal()` instead of the name comparisons. You will have to use some explicit loop, [quantified expressions] should get handy for that. > > Regards from Lake Constance, Germany, > Jens Erat > > [quantified expressions]: http://www.w3.org/TR/xpath20/#id-quantified-expressions >
JE
Jens Erat20 May 2013 16:35 #
You don't really need them, they're just syntactical sugar making the code more readable for everybody familiar with functional programming.
- `head($sequence)` could be written as `$sequence[1]`
- `tail($sequence)` could be written as `$sequence[position()>1]`--
Jens Erat
[phone]: tel:+49-151-56961126
[mail]: mailto:email at jenserat.de
[jabber]: xmpp:jabber at jenserat.de
[web]: http://www.jenserat.de
PGP: 350E D9B6 9ADC 2DED F5F2 8549 CBC2 613C D745 722B
Quoted text · Marco Lettere · 41 lines
Am 20.05.2013 um 16:31 schrieb Marco Lettere <marco.lettere at dedalus.eu>: > Thanks a lot. > I'm really wondering how I was able to overlook "head" and "tail" .... maybe the age .... :-( > > M. > > On 05/20/2013 03:44 PM, Jens Erat wrote: >> hi Marco, >> >> using recursion is easily possible (and the only way to solve that problem without using maps), just write a small XQuery function like >> >> declare function local:interprete($operations as item()*, $set as item()*) as item()* { >> let $op := head($operations) >> let $ops := tail($operations) >> let $intermediate := >> switch($op/@operator) >> case "UNION" return ($set, $op/item[not(@name = $set/@name)]) >> case "INTERSECT" return $set[@name = $op/item/@name] >> case "DIFFERENCE" return $set[not(@name = $op/item/@name)] >> default return error() >> return >> if ($ops) >> then >> local:interprete($ops, $intermediate) >> else $intermediate >> }; >> >> Which you would call using `local:interpret(//set, ())`. I guess the code should be small enough to be self-explaining. I seems to work, but I didn't test with much more than the input you provided, better do some additional tests on production data before using it. >> >> If you want to compare whole nodes instead of their name attribute, use `fn:deep-equal()` instead of the name comparisons. You will have to use some explicit loop, [quantified expressions] should get handy for that. >> >> Regards from Lake Constance, Germany, >> Jens Erat >> >> [quantified expressions]: http://www.w3.org/TR/xpath20/#id-quantified-expressions >> > > _______________________________________________ > BaseX-Talk mailing list > BaseX-Talk at mailman.uni-konstanz.de > https://mailman.uni-konstanz.de/mailman/listinfo/basex-talk
ML
Marco Lettere20 May 2013 16:42 #
Yep!
Of course I meant it conceptually! (ROFL).
Luckily not that burned out yet! :-D
Thanks again.
M.
Quoted text · Jens Erat · 6 lines
On 05/20/2013 04:35 PM, Jens Erat wrote: > You don't really need them, they're just syntactical sugar making the code more readable for everybody familiar with functional programming. > > - `head($sequence)` could be written as `$sequence[1]` > - `tail($sequence)` could be written as `$sequence[position()>1]` >
Written for BaseX 7.6. BaseX may have changed since: please check the current documentation.
⚡Generated with XQuery