Currently I'm doing some xquery like following.
XML document:
<?xml version="1.0" encoding="UTF-8"?>
<animal>
<dog name="ada">
<color>black</color>
<byear>2012</byear>
</dog>
<dog name="bob">
<color>black</color>
<byear>2011</byear>
</dog>
<cat name="cathy">
<color>black</color>
<byear>2010</byear>
</cat>
<cat name="dione">
<color>brown</color>
<byear>2009</byear>
</cat>
</animal>
Expected output:
<?xml version="1.0" encoding="UTF-8"?>
<animal>
<color>black</color>
<dog name="ada">
<byear>2012</byear>
</dog>
<dog name="bob">
<byear>2011</byear>
</dog>
<cat name="cathy">
<byear>2010</byear>
</cat>
</animal>
My code looks like:
<animal>
{ for $a in distinct-values(//animal/*/color)
return <color>{$a}</color>
{ for $b in //animal/*[color=$a]
where $b//color="black"
return $b/* except $b/color
</animal>
and the output was good but it does not include the parent tag (e.g. <dog name="ada"> </dog>
).
Besides, I had also tried something like return $b except $b/color
and the output this time included parent tag however it also included the "color" on the child tag. Any idea?
In normal XQuery you cannot just return a part of a node. You either return the entire node, with all its children/descendants, or you select some of the children/descendants and return those nodes entirely.
What you can do instead is to create a new node with the same name as the old one with element {node-name(...)} {...}
and then copy the children you want from the old node to the new one.
Something like:
<animal>
{ for $a in distinct-values(//animal/*/color)
return (
<color>{$a}</color>,
for $b in //animal/*[color=$a]
return element {node-name($b)} {$b / @*, $b/node() except $b/color }
)
}
</animal>
(With the XQuery Update extension you could also remove the nodes you do not want instead copying them)