Chapter 9: Advanced Queries
Example 9-1. Useful function: add-attribute (see also functx:add-attributes)
declare namespace functx = "http://www.functx.com";
declare function functx:add-attribute
($element as element(), $name as xs:string,
$value as xs:anyAtomicType?) as element() {
element { node-name($element)}
{ attribute {$name} {$value},
$element/@*,
$element/node() }
};
Example 9-2. Useful function: remove-attribute (see also functx:remove-attributes)
declare namespace functx = "http://www.functx.com";
declare function functx:remove-attributes
($element as element(), $names as xs:string*) as element() {
element { node-name($element)}
{ $element/@*[not(name() = $names)],
$element/node() }
};
Example 9-3. Useful function: remove-attribute-deep (see also functx:remove-attributes-deep)
declare namespace functx = "http://www.functx.com";
declare function functx:remove-attributes-deep
($element as element(), $names as xs:string*) as element() {
element { node-name($element)}
{ $element/@*[not(name() = $names)],
for $child in $element/node()
return if ($child instance of element())
then functx:remove-attributes-deep($child, $names)
else $child }
};
Example 9-4. Useful function: remove-elements-deep (see also functx:remove-elements-deep)
declare namespace functx = "http://www.functx.com";
declare function functx:remove-elements-deep
($element as element(), $names as xs:string*) as element() {
element {node-name($element)}
{$element/@*,
for $child in $element/node()
return if ($child instance of element())
then if ($child[name() = $names])
then ()
else functx:remove-elements-deep($child, $names)
else $child }
};
Example 9-5. Useful function: remove-elements-not-contents (see also functx:remove-elements-not-contents)
declare namespace functx = "http://www.functx.com";
declare function functx:remove-elements-not-contents
($element as element(), $names as xs:string*) as element() {
element {node-name($element)}
{$element/@*,
for $child in $element/node()
return if ($child instance of element())
then if ($child[name() = $names])
then $child/node()
else functx:remove-elements-not-contents($child, $names)
else $child }
};
Example 9-6. Useful function: change-elem-names (see also functx:change-element-names-deep)
declare function local:change-elem-names
($nodes as node()*, $old-names as xs:string+,
$new-names as xs:string+) as node()* {
if (count($old-names) != count($new-names))
then error(xs:QName("Different_Number_Of_Names"))
else for $node in $nodes
return if ($node instance of element())
then let $newName :=
if (local-name($node) = $old-names)
then $new-names[index-of($old-names, local-name($node))]
else local-name($node)
return element {$newName}
{$node/@*,
local:change-elem-names($node/node(),
$old-names, $new-names)}
else $node
};
Example 9-7. Using the change-elem-names function
declare function local:change-elem-names
($nodes as node()*, $old-names as xs:string+,
$new-names as xs:string+) as node()* {
if (count($old-names) != count($new-names))
then error(xs:QName("Different_Number_Of_Names"))
else for $node in $nodes
return if ($node instance of element())
then let $newName :=
if (local-name($node) = $old-names)
then $new-names[index-of($old-names, local-name($node))]
else local-name($node)
return element {$newName}
{$node/@*,
local:change-elem-names($node/node(),
$old-names, $new-names)}
else $node
};
let $order := doc("order.xml")/order
let $oldNames := ("order", "item")
let $newNames := ("purchaseOrder", "purchasedItem")
return local:change-elem-names($order, $oldNames, $newNames)
Example 9-8. Attempting to use a counter variable
let $count := 0
for $prod in doc("catalog.xml")//product[@dept = ("ACC", "WMN")]
let $count := $count + 1
return <p>{$count}. {data($prod/name)}</p>
Example 9-9. Attempting to use the position function
for $prod in doc("catalog.xml")//product[@dept = ("ACC", "WMN")]
return <p>{$prod/position()}. {data($prod/name)}</p>
Example 9-10. Using a positional variable in a for clause
for $prod at $count in doc("catalog.xml")//product[@dept = ("ACC", "WMN")]
return <p>{$count}. {data($prod/name)}</p>
Example 9-11. Attempting to use a positional variable with a where clause
for $prod at $count in doc("catalog.xml")//product
where $prod/@dept = ("ACC", "MEN")
order by $prod/name
return <p>{$count}. {data($prod/name)}</p>
Example 9-12. Embedding the where clause
let $sortedProds := for $prod in doc("catalog.xml")//product
where $prod/@dept = "ACC" or $prod/@dept = "MEN"
order by $prod/name
return $prod
for $sortedProd at $count in $sortedProds
return <p>{$count}. {data($sortedProd/name)}</p>
Example 9-13. Testing for the last item
<p>{ let $prods := doc("catalog.xml")//product
let $numProds := count($prods)
for $prod at $count in $prods
return if ($count = $numProds)
then concat($prod/name,".")
else concat($prod/name,",")
}</p>
Example 9-14. Testing for the last item using the is operator
<p>{ let $prods := doc("catalog.xml")//product
for $prod in $prods
return if ($prod is $prods[last()])
then concat($prod/name,".")
else concat($prod/name,", ")
}</p>
Example 9-15. Converting values without a lookup table
let $cat := doc("catalog.xml")/catalog
for $dept in distinct-values($cat/product/@dept)
return <li>Department: {if ($dept = "ACC")
then "Accessories"
else if ($dept = "MEN")
then "Menswear"
else if ($dept = "WMN")
then "Womens"
else ()
} ({$dept})</li>
Example 9-16. Converting values with a lookup table
let $deptNames := <deptNames>
<dept code="ACC" name="Accessories"/>
<dept code="MEN" name="Menswear"/>
<dept code="WMN" name="Womens"/>
</deptNames>
let $cat := doc("catalog.xml")/catalog
for $dept in distinct-values($cat/product/@dept)
return <li>Department: {data($deptNames/dept[@code = $dept]/@name)
} ({$dept})</li>
Example 9-17. Reducing complexity
let $tempResults:= for $item in doc("order.xml")//item,
$product in doc("catalog.xml")//product
where $item/@num = $product/number
return <item num="{$item/@num}" name="{$product/name}"
color="{$item/@color}"
quant="{$item/@quantity}"/>
return <table>
<tr>
<th>#</th><th>Name</th><th>Color</th><th>Quan</th>
</tr>
{for $lineItem in $tempResults
return <tr>
<td>{data($lineItem/@num)}</td>
<td>{data($lineItem/@name)}</td>
<td>{data($lineItem/@color)}</td>
<td>{data($lineItem/@quant)}</td>
</tr>
}
</table>
|