N. America: 800 876 3101 | World: 44 (0) 1753 218 930

Can I group elements based on their relative positions?

My XML is structured this way:

<books>
    <title>title 1</title>
    <price>100</price>
    <date>01012007</date>
    <title>title 2</title>
    <price>90</price>
    <publisher>pub 1</publisher>
</books>

The XML file contains a long list of books, about which only the <title> element is guaranteed to be always present.

How can I modify the XML document using XQuery to group each book's properties under a single element, like this:

<books>
    <book>
        <title>title 1</title>
        <price>100</price>
        <date>01012007</date>
    </book>
    <book>
        <title>title 2</title>
        <price>90</price>
        <publisher>pub 1</publisher>
    </book>
</books>

The simplest solution we can think of is this:

<books> {
    for $title in /books/title
    return
        <book> {
            $title,
            let $nextTitle := $title/following-sibling::title[1]
            for $prop in $title/following-sibling::*[local-name() != "title"]
            where empty($nextTitle) or $prop << $nextTitle
            return $prop
        } </book>
} </books>

In this solution, we basically iterate over all the <title> elements. For each of them we find the next <title> element (if any), and then we iterate through all the elements contained in between the two <title> elements.

The code can become a bit easier to read and more resuable if we introduce a function, like this:

declare function local:getRelatedSiblings($item) {
      let $nextItem := $item/following-sibling::*[local-name()=$item/local-name()][1]
      for $related in $item/following-sibling::*[local-name()!=$item/local-name()]
      where empty($nextItem) or $related << $nextItem
      return $related
 };
 
 <books> {
    for $title in /books/title
    return
        <book> {
            $title,
            for $prop in local:getRelatedSiblings($title)
            return $prop
        } </book>
} </books>


Next Question!

What's the proper way to use the node sequence (<< and >>) operators?

Submit Your DataDirect XQuery Tip or Trick

Tell us your XQuery Tip or Trick – if it gets published on our site, you’ll receive a

$10.00 Amazon.com
Gift Certificate!

Submit your tip or trick today.