XQuery

XQuery

(pwalmsley@datypic.com)

ISBN: 0596006349

1st edition, , O'Reilly Media, Inc.

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>
Datypic XQuery Services