Table of contents

If you want to run the examples yourself, they are included in the magic/xml package. Whitespace has been changed for easier reading. The original use cases are available on W3C website.

Input for PARTS - partlist.xml

[Table of contents][Back to home page]
 1 <?xml version="1.0" encoding="ISO-8859-1"?>
 2 <partlist>
 3   <part partid="0" name="car"/>
 4   <part partid="1" partof="0" name="engine"/>
 5   <part partid="2" partof="0" name="door"/>
 6   <part partid="3" partof="1" name="piston"/>
 7   <part partid="4" partof="2" name="window"/>
 8   <part partid="5" partof="2" name="lock"/>
 9   <part partid="10" name="skateboard"/>
10   <part partid="11" partof="10" name="board"/>
11   <part partid="12" partof="10" name="wheel"/>
12   <part partid="20" name="canoe"/>
13 </partlist>

PARTS - Q1

[Table of contents][Back to home page]

Convert the sample document from "partlist" format to "parttree" format (see DTD section for definitions). In the result document, part containment is represented by containment of one <part> element inside another. Each part that is not part of any other part should appear as a separate top-level element in the output document.

magic/xml solution

 1 def parts_of(parts, partid)
 2     res = []
 3     parts.each{|p|
 4         if p[:partof] == partid
 5             a = p.attrs.dup
 6             a.delete :partof
 7             res << xml(:part, a, parts_of(parts, p[:partid]))
 8         end
 9     }
10     res
11 end
12 
13 XML.parttree! {
14     parts = XML.load('partlist.xml').children(:part)
15     add! parts_of(parts, nil)
16 }

XQuery solution

declare function local:one_level($p as element()) as element()
{
    <part partid="{ $p/@partid }"
          name="{ $p/@name }" >
        {
            for $s in doc("partlist.xml")//part
            where $s/@partof = $p/@partid
            return local:one_level($s)
        }
    </part>
};

<parttree>
  {
    for $p in doc("partlist.xml")//part[empty(@partof)]
    return local:one_level($p)
  }
</parttree>

Expected output

 1 <parttree>
 2     <part partid="0" name="car">
 3         <part partid="1" name="engine">
 4             <part partid="3" name="piston"/>
 5         </part>
 6         <part partid="2" name="door">
 7             <part partid="4" name="window"/>
 8             <part partid="5" name="lock"/>
 9         </part>
10     </part>
11     <part partid="10" name="skateboard">
12         <part partid="11" name="board"/>
13         <part partid="12" name="wheel"/>
14     </part>
15     <part partid="20" name="canoe"/>
16 </parttree>

Input for RDB - bids.xml

[Table of contents][Back to home page]
 1 <bids>
 2 <bid_tuple>
 3 <userid>U02</userid>
 4 <itemno>1001</itemno>
 5 <bid>35</bid>
 6 <bid_date>1999-01-07</bid_date></bid_tuple>
 7 <bid_tuple>
 8 <userid>U04</userid>
 9 <itemno>1001</itemno>
10 <bid>40</bid>
11 <bid_date>1999-01-08</bid_date></bid_tuple>
12 <bid_tuple>
13 <userid>U02</userid>
14 <itemno>1001</itemno>
15 <bid>45</bid>
16 <bid_date>1999-01-11</bid_date></bid_tuple>
17 <bid_tuple>
18 <userid>U04</userid>
19 <itemno>1001</itemno>
20 <bid>50</bid>
21 <bid_date>1999-01-13</bid_date></bid_tuple>
22 <bid_tuple>
23 <userid>U02</userid>
24 <itemno>1001</itemno>
25 <bid>55</bid>
26 <bid_date>1999-01-15</bid_date></bid_tuple>
27 <bid_tuple>
28 <userid>U01</userid>
29 <itemno>1002</itemno>
30 <bid>400</bid>
31 <bid_date>1999-02-14</bid_date></bid_tuple>
32 <bid_tuple>
33 <userid>U02</userid>
34 <itemno>1002</itemno>
35 <bid>600</bid>
36 <bid_date>1999-02-16</bid_date></bid_tuple>
37 <bid_tuple>
38 <userid>U03</userid>
39 <itemno>1002</itemno>
40 <bid>800</bid>
41 <bid_date>1999-02-17</bid_date></bid_tuple>
42 <bid_tuple>
43 <userid>U04</userid>
44 <itemno>1002</itemno>
45 <bid>1000</bid>
46 <bid_date>1999-02-25</bid_date></bid_tuple>
47 <bid_tuple>
48 <userid>U02</userid>
49 <itemno>1002</itemno>
50 <bid>1200</bid>
51 <bid_date>1999-03-02</bid_date></bid_tuple>
52 <bid_tuple>
53 <userid>U04</userid>
54 <itemno>1003</itemno>
55 <bid>15</bid>
56 <bid_date>1999-01-22</bid_date></bid_tuple>
57 <bid_tuple>
58 <userid>U05</userid>
59 <itemno>1003</itemno>
60 <bid>20</bid>
61 <bid_date>1999-02-03</bid_date></bid_tuple>
62 <bid_tuple>
63 <userid>U01</userid>
64 <itemno>1004</itemno>
65 <bid>40</bid>
66 <bid_date>1999-03-05</bid_date></bid_tuple>
67 <bid_tuple>
68 <userid>U03</userid>
69 <itemno>1007</itemno>
70 <bid>175</bid>
71 <bid_date>1999-01-25</bid_date></bid_tuple>
72 <bid_tuple>
73 <userid>U05</userid>
74 <itemno>1007</itemno>
75 <bid>200</bid>
76 <bid_date>1999-02-08</bid_date></bid_tuple>
77 <bid_tuple>
78 <userid>U04</userid>
79 <itemno>1007</itemno>
80 <bid>225</bid>
81 <bid_date>1999-02-12</bid_date></bid_tuple></bids>

Input for RDB - items.xml

[Table of contents][Back to home page]
 1 <items>
 2 <item_tuple>
 3 <itemno>1001</itemno>
 4 <description>Red Bicycle</description>
 5 <offered_by>U01</offered_by>
 6 <start_day>1999-01-05</start_day>
 7 <end_day>1999-01-20</end_day>
 8 <reserve_price>40</reserve_price></item_tuple>
 9 <item_tuple>
10 <itemno>1002</itemno>
11 <description>Motorcycle</description>
12 <offered_by>U02</offered_by>
13 <start_day>1999-02-11</start_day>
14 <end_day>1999-03-15</end_day>
15 <reserve_price>500</reserve_price></item_tuple>
16 <item_tuple>
17 <itemno>1003</itemno>
18 <description>Old Bicycle</description>
19 <offered_by>U02</offered_by>
20 <start_day>1999-01-10</start_day>
21 <end_day>1999-02-20</end_day>
22 <reserve_price>25</reserve_price></item_tuple>
23 <item_tuple>
24 <itemno>1004</itemno>
25 <description>Tricycle</description>
26 <offered_by>U01</offered_by>
27 <start_day>1999-02-25</start_day>
28 <end_day>1999-03-08</end_day>
29 <reserve_price>15</reserve_price></item_tuple>
30 <item_tuple>
31 <itemno>1005</itemno>
32 <description>Tennis Racket</description>
33 <offered_by>U03</offered_by>
34 <start_day>1999-03-19</start_day>
35 <end_day>1999-04-30</end_day>
36 <reserve_price>20</reserve_price></item_tuple>
37 <item_tuple>
38 <itemno>1006</itemno>
39 <description>Helicopter</description>
40 <offered_by>U03</offered_by>
41 <start_day>1999-05-05</start_day>
42 <end_day>1999-05-25</end_day>
43 <reserve_price>50000</reserve_price></item_tuple>
44 <item_tuple>
45 <itemno>1007</itemno>
46 <description>Racing Bicycle</description>
47 <offered_by>U04</offered_by>
48 <start_day>1999-01-20</start_day>
49 <end_day>1999-02-20</end_day>
50 <reserve_price>200</reserve_price></item_tuple>
51 <item_tuple>
52 <itemno>1008</itemno>
53 <description>Broken Bicycle</description>
54 <offered_by>U01</offered_by>
55 <start_day>1999-02-05</start_day>
56 <end_day>1999-03-06</end_day>
57 <reserve_price>25</reserve_price></item_tuple></items>

Input for RDB - users.xml

[Table of contents][Back to home page]
 1 <users>
 2 <user_tuple>
 3 <userid>U01</userid>
 4 <name>Tom Jones</name>
 5 <rating>B</rating></user_tuple>
 6 <user_tuple>
 7 <userid>U02</userid>
 8 <name>Mary Doe</name>
 9 <rating>A</rating></user_tuple>
10 <user_tuple>
11 <userid>U03</userid>
12 <name>Dee Linquent</name>
13 <rating>D</rating></user_tuple>
14 <user_tuple>
15 <userid>U04</userid>
16 <name>Roger Smith</name>
17 <rating>C</rating></user_tuple>
18 <user_tuple>
19 <userid>U05</userid>
20 <name>Jack Sprat</name>
21 <rating>B</rating></user_tuple>
22 <user_tuple>
23 <userid>U06</userid>
24 <name>Rip Van Winkle</name>
25 <rating>B</rating></user_tuple></users>

RDB - Q1

[Table of contents][Back to home page]

List the item number and description of all bicycles that currently have an auction in progress, ordered by item number.

magic/xml solution

 1 current_day = "1999-01-31"
 2 
 3 items = XML.load('items.xml').sort_by{|i| i[:@itemno].to_i}
 4 XML.result! {
 5     items.each(XML) {|i|
 6         next unless current_day.between?(i[:@start_day], i[:@end_day]) and i[:@description] =~ /Bicycle/
 7         item_tuple!(i.children(:itemno), i.children(:description))
 8     }
 9 }

XQuery solution

<result>
  {
    for $i in doc("items.xml")//item_tuple
    where $i/start_date <= current-date()
      and $i/end_date >= current-date() 
      and contains($i/description, "Bicycle")
    order by $i/itemno
    return
        <item_tuple>
            { $i/itemno }
            { $i/description }
        </item_tuple>
  }
</result>

Expected output

 1 <result>
 2     <item_tuple>
 3         <itemno>1003</itemno>
 4         <description>Old Bicycle</description>
 5     </item_tuple>
 6     <item_tuple>
 7         <itemno>1007</itemno>
 8         <description>Racing Bicycle</description>
 9     </item_tuple>
10 </result>

RDB - Q2

[Table of contents][Back to home page]

For all bicycles, list the item number, description, and highest bid (if any), ordered by item number.

magic/xml solution

 1 items = XML.load('items.xml').sort_by{|i| i[:@itemno].to_i}
 2 bids  = XML.load('bids.xml')
 3 
 4 XML.result! {
 5     items.each({:@description => /Bicycle/}){|i|
 6         item_tuple! {
 7             add! i.children(:itemno)
 8             add! i.children(:description)
 9 
10             item_bids = bids.find_all{|b| b.is_a? XML and b[:@itemno] == i[:@itemno] }
11             high_bid! item_bids.map{|b| b[:@bid].to_i}.max
12         }
13     }
14 }

XQuery solution

<result>
  {
    for $i in doc("items.xml")//item_tuple
    let $b := doc("bids.xml")//bid_tuple[itemno = $i/itemno]
    where contains($i/description, "Bicycle")
    order by $i/itemno
    return
        <item_tuple>
            { $i/itemno }
            { $i/description }
            <high_bid>{ max($b/bid) }</high_bid>
        </item_tuple>
  }
</result>

Expected output

 1 <result>
 2   <item_tuple>
 3     <itemno>1001</itemno>
 4     <description>Red Bicycle</description>
 5     <high_bid>55</high_bid>
 6   </item_tuple>
 7   <item_tuple>
 8     <itemno>1003</itemno>
 9     <description>Old Bicycle</description>
10     <high_bid>20</high_bid>
11   </item_tuple>
12   <item_tuple>
13     <itemno>1007</itemno>
14     <description>Racing Bicycle</description>
15     <high_bid>225</high_bid>
16   </item_tuple>
17   <item_tuple>
18     <itemno>1008</itemno>
19     <description>Broken Bicycle</description>
20     <high_bid></high_bid>
21   </item_tuple>
22 </result>

RDB - Q3

[Table of contents][Back to home page]

Find cases where a user with a rating worse (alphabetically, greater) than "C" is offering an item with a reserve price of more than 1000.

magic/xml solution

 1 items = XML.load('items.xml')
 2 users = XML.load('users.xml')
 3 
 4 XML.result! {
 5     users.each(XML){|u|
 6         next unless u[:@rating] > "C"
 7         items.each(XML){|i|
 8             next unless i[:@reserve_price].to_i > 1000
 9             warning!(u.child(:name), u.child(:rating), i.child(:description), i.child(:reserve_price))
10         }
11     }
12 }

XQuery solution

<result>
  {
    for $u in doc("users.xml")//user_tuple
    for $i in doc("items.xml")//item_tuple
    where $u/rating > "C" 
       and $i/reserve_price > 1000 
       and $i/offered_by = $u/userid
    return
        <warning>
            { $u/name }
            { $u/rating }
            { $i/description }
            { $i/reserve_price }
        </warning>
  }
</result>

Expected output

1 <result>
2     <warning>
3         <name>Dee Linquent</name>
4         <rating>D</rating>
5         <description>Helicopter</description>
6         <reserve_price>50000</reserve_price>
7     </warning>
8 </result>

RDB - Q4

[Table of contents][Back to home page]

List item numbers and descriptions of items that have no bids. For bicycle(s) offered by Tom Jones that have received a bid, list the item number, description, highest bid, and name of the highest bidder, ordered by item number.

magic/xml solution

 1 items = XML.load('items.xml')
 2 bids = XML.load('bids.xml')
 3 
 4 XML.result!{
 5     items.each(XML){|i|
 6         next if bids.any?{|b| b.is_a? XML and b[:@itemno] == i[:@itemno]}
 7         no_bid_item!(i.child(:itemno), i.child(:description))
 8     }
 9 }

XQuery solution

<result>
  {
    for $i in doc("items.xml")//item_tuple
    where empty(doc("bids.xml")//bid_tuple[itemno = $i/itemno])
    return
        <no_bid_item>
            { $i/itemno }
            { $i/description }
        </no_bid_item>
  }
</result>

Expected output

 1 <result>
 2     <no_bid_item>
 3         <itemno>1005</itemno>
 4         <description>Tennis Racket</description>
 5     </no_bid_item>
 6     <no_bid_item>
 7         <itemno>1006</itemno>
 8         <description>Helicopter</description>
 9     </no_bid_item>
10     <no_bid_item>
11         <itemno>1008</itemno>
12         <description>Broken Bicycle</description>
13     </no_bid_item>
14 </result>

RDB - Q5

[Table of contents][Back to home page]

magic/xml solution

 1 items = XML.load('items.xml').sort_by{|i| i[:@itemno].to_i}
 2 users = XML.load('users.xml')
 3 bids  = XML.load('bids.xml')
 4 
 5 XML.result! {
 6     users.each({:@name => "Tom Jones"}) {|seller|
 7         items.each({:@offered_by => seller[:@userid], :@description => /Bicycle/}) {|item|
 8             bids.each({:@itemno => item[:@itemno]}) {|highbid|
 9                 users.each({:@userid => highbid[:@userid]}) {|buyer|
10                     best_bid = bids.find_all{|b| b.is_a? XML and b[:@itemno] == item[:@itemno]}.map{|b| b[:@bid].to_i}.max
11                     next unless highbid[:@bid].to_i == best_bid
12                     
13                     jones_bike! {
14                         add! item.child(:itemno)
15                         add! item.child(:description)
16                         high_bid! highbid.child(:bid)
17                         high_bidder! buyer.child(:name)
18                     }
19                 }
20             }
21         }
22     }
23 }

XQuery solution

<result>
  {
    for $seller in doc("users.xml")//user_tuple,
        $buyer in  doc("users.xml")//user_tuple,
        $item in  doc("items.xml")//item_tuple,
        $highbid in  doc("bids.xml")//bid_tuple
    where $seller/name = "Tom Jones"
      and $seller/userid  = $item/offered_by
      and contains($item/description , "Bicycle")
      and $item/itemno  = $highbid/itemno
      and $highbid/userid  = $buyer/userid
      and $highbid/bid = max(
                              doc("bids.xml")//bid_tuple
                                [itemno = $item/itemno]/bid
                         )
    order by ($item/itemno)
    return
        <jones_bike>
            { $item/itemno }
            { $item/description }
            <high_bid>{ $highbid/bid }</high_bid>
            <high_bidder>{ $buyer/name }</high_bidder>
        </jones_bike>
  }
</result>

Expected output

 1 <result>
 2     <jones_bike>
 3         <itemno>1001</itemno>
 4         <description>Red Bicycle</description>
 5         <high_bid>
 6             <bid>55</bid>
 7         </high_bid>
 8         <high_bidder>
 9             <name>Mary Doe</name>
10         </high_bidder>
11     </jones_bike>
12 </result>

RDB - Q6

[Table of contents][Back to home page]

For each item whose highest bid is more than twice its reserve price, list the item number, description, reserve price, and highest bid.

magic/xml solution

 1 items = XML.load('items.xml')
 2 bids  = XML.load('bids.xml')
 3 
 4 XML.result! {
 5     items.each(XML){|item|
 6 z = bids.find_all{|b| b.is_a? XML and b[:@itemno] == item[:@itemno]}.map{|b| b[:@bid].to_i}.max
 7         next unless z and item[:@reserve_price].to_i * 2 < z
 8         successful_item! {
 9             add! item.child(:itemno)
10             add! item.child(:description)
11             add! item.child(:reserve_price)
12             high_bid! z
13         }
14     }
15 }

XQuery solution

<result>
  {
    for $item in doc("items.xml")//item_tuple
    let $b := doc("bids.xml")//bid_tuple[itemno = $item/itemno]
    let $z := max($b/bid)
    where $item/reserve_price * 2 < $z
    return
        <successful_item>
            { $item/itemno }
            { $item/description }
            { $item/reserve_price }
            <high_bid>{$z }</high_bid>
         </successful_item>
  }
</result>

Expected output

 1 <result>
 2     <successful_item>
 3         <itemno>1002</itemno>
 4         <description>Motorcycle</description>
 5         <reserve_price>500</reserve_price>
 6         <high_bid>1200</high_bid>
 7     </successful_item>
 8     <successful_item>
 9         <itemno>1004</itemno>
10         <description>Tricycle</description>
11         <reserve_price>15</reserve_price>
12         <high_bid>40</high_bid>
13     </successful_item>
14 </result>

RDB - Q7

[Table of contents][Back to home page]

Find the highest bid ever made for a bicycle or tricycle.

magic/xml solution

1 items = XML.load('items.xml')
2 bids  = XML.load('bids.xml')
3 
4 allbikes = items.children({:@description => /Bicycle|Tricycle/}).map{|item| item[:@itemno]}
5 
6 XML.high_bid! {
7     add! bids.find_all{|b| b.is_a? XML and allbikes.include? b[:@itemno]}.map{|b| b[:@bid].to_i}.max
8 }

XQuery solution

let $allbikes := doc("items.xml")//item_tuple
                    [contains(description, "Bicycle") 
                     or contains(description, "Tricycle")]
let $bikebids := doc("bids.xml")//bid_tuple[itemno = $allbikes/itemno]
return
    <high_bid>
      { 
        max($bikebids/bid) 
      }
    </high_bid>

Expected output

1 <high_bid>225</high_bid>

RDB - Q8

[Table of contents][Back to home page]

How many items were actioned (auction ended) in March 1999?

magic/xml solution

1 XML.item_count! XML.load('items.xml').find_all{|item| item.is_a? XML and item[:@end_day] =~ /^1999-03/}.size

XQuery solution

let $item := doc("items.xml")//item_tuple
  [end_date >= xs:date("1999-03-01") and end_date <= xs:date("1999-03-31")]
return
    <item_count>
      { 
        count($item) 
      }
    </item_count>

Expected output

1 <item_count>3</item_count>

RDB - Q9

[Table of contents][Back to home page]

List the number of items auctioned each month in 1999 for which data is available, ordered by month.

magic/xml solution

 1 items = XML.load('items.xml').children(:item_tuple)
 2 
 3 XML.result! {
 4     items.map{|item| item[:@end_day] =~ /^1999-(\d+)/; $1.to_i}.sort.uniq.each{|m|
 5         monthly_result! {
 6             month! m
 7             item_count!(items.find_all{|item| item[:@end_day] =~ /1999-(\d+)/; $1.to_i==m}.size)
 8         }
 9     }
10 }

XQuery solution

<result>
  {
    let $end_dates := doc("items.xml")//item_tuple/end_date
    for $m in distinct-values(for $e in $end_dates 
                              return month-from-date($e))
    let $item := doc("items.xml")
        //item_tuple[year-from-date(end_date) = 1999 
                     and month-from-date(end_date) = $m]
    order by $m
    return
        <monthly_result>
            <month>{ $m }</month>
            <item_count>{ count($item) }</item_count>
        </monthly_result>
  }
</result>

Expected output

 1 <result>
 2     <monthly_result>
 3         <month>1</month>
 4         <item_count>1</item_count>
 5     </monthly_result>
 6     <monthly_result>
 7         <month>2</month>
 8         <item_count>2</item_count>
 9     </monthly_result>
10     <monthly_result>
11         <month>3</month>
12         <item_count>3</item_count>
13     </monthly_result>
14     <monthly_result>
15         <month>4</month>
16         <item_count>1</item_count>
17     </monthly_result>
18     <monthly_result>
19         <month>5</month>
20         <item_count>1</item_count>
21     </monthly_result>
22 </result>

RDB - Q10

[Table of contents][Back to home page]

For each item that has received a bid, list the item number, the highest bid, and the name of the highest bidder, ordered by item number.

magic/xml solution

 1 users = XML.load('users.xml')
 2 bids  = XML.load('bids.xml').sort_by{|b| b[:@itemno].to_i}
 3 
 4 XML.result! {
 5     bids.each{|highbid|
 6         next if bids.any?{|b| b[:@itemno] == highbid[:@itemno] and b[:@bid].to_i > highbid[:@bid].to_i}
 7         users.children({:@userid => highbid[:@userid]}){|user|
 8             high_bid! {
 9                 add! highbid.child(:itemno)
10                 add! highbid.child(:bid)
11                 bidder! user[:@name]
12             }
13         }
14     }
15 }

XQuery solution

<result>
 {
    for $highbid in doc("bids.xml")//bid_tuple,
        $user in doc("users.xml")//user_tuple
    where $user/userid = $highbid/userid 
      and $highbid/bid = max(doc("bids.xml")//bid_tuple[itemno=$highbid/itemno]/bid)
    order by $highbid/itemno
    return
        <high_bid>
            { $highbid/itemno }
            { $highbid/bid }
            <bidder>{ $user/name/text() }</bidder>
        </high_bid>
  }
</result>

Expected output

 1 <result>
 2     <high_bid>
 3         <itemno>1001</itemno>
 4         <bid>55</bid>
 5         <bidder>Mary Doe</bidder>
 6     </high_bid>
 7     <high_bid>
 8         <itemno>1002</itemno>
 9         <bid>1200</bid>
10         <bidder>Mary Doe</bidder>
11     </high_bid>
12     <high_bid>
13         <itemno>1003</itemno>
14         <bid>20</bid>
15         <bidder>Jack Sprat</bidder>
16     </high_bid>
17     <high_bid>
18         <itemno>1004</itemno>
19         <bid>40</bid>
20         <bidder>Tom Jones</bidder>
21     </high_bid>
22     <high_bid>
23         <itemno>1007</itemno>
24         <bid>225</bid>
25         <bidder>Roger Smith</bidder>
26     </high_bid>
27 </result>

RDB - Q11

[Table of contents][Back to home page]

List the item number and description of the item(s) that received the highest bid ever recorded, and the amount of that bid.

magic/xml solution

 1 items = XML.load('items.xml')
 2 bids  = XML.load('bids.xml')
 3 
 4 highbid = bids.children.children(:bid).map{|b| b.text.to_i}.max.to_s
 5 
 6 XML.result! {
 7     items.each(XML){|item|
 8         bids.each({:@itemno => item[:@itemno], :@bid => highbid}) {|b|
 9             expensive_item! {
10                 add! item.child(:itemno)
11                 add! item.child(:description)
12                 high_bid! highbid
13             }
14         }
15     }
16 }

XQuery solution

let $highbid := max(doc("bids.xml")//bid_tuple/bid)
return
    <result>
     {
        for $item in doc("items.xml")//item_tuple,
            $b in doc("bids.xml")//bid_tuple[itemno = $item/itemno]
        where $b/bid = $highbid
        return
            <expensive_item>
                { $item/itemno }
                { $item/description }
                <high_bid>{ $highbid }</high_bid>
            </expensive_item>
     }
    </result>

Expected output

1 <result>
2     <expensive_item>
3         <itemno>1002</itemno>
4         <description>Motorcycle</description>
5         <high_bid>1200</high_bid>
6     </expensive_item>
7 </result>

RDB - Q12

[Table of contents][Back to home page]

List the item number and description of the item(s) that received the largest number of bids, and the number of bids it (or they) received.

magic/xml solution

 1 items = XML.load('items.xml')
 2 bids  = XML.load('bids.xml').children(:bid_tuple)
 3 
 4 XML.result! {
 5     bids_per_item = Hash.new([])
 6     bids.each{|bid|
 7         bids_per_item[bid[:@itemno]] += [bid]
 8     }
 9     max_bid_count = bids_per_item.map{|k,v| v.size}.max
10 
11     items.each(XML){|item|
12         next unless bids_per_item[item[:@itemno]].size == max_bid_count
13         popular_item! {
14             add! item.child(:itemno)
15             add! item.child(:description)
16             bid_count! max_bid_count
17         }
18     }
19 }

XQuery solution

declare function local:bid_summary()
  as element()*
{
    for $i in distinct-values(doc("bids.xml")//itemno)
    let $b := doc("bids.xml")//bid_tuple[itemno = $i]
    return
        <bid_count>
            <itemno>{ $i }</itemno>
            <nbids>{ count($b) }</nbids>
        </bid_count>
};

<result>
 {
    let $bid_counts := local:bid_summary(),
        $maxbids := max($bid_counts/nbids),
        $maxitemnos := $bid_counts[nbids = $maxbids]
    for $item in doc("items.xml")//item_tuple,
        $bc in $bid_counts
    where $bc/nbids =  $maxbids and $item/itemno = $bc/itemno
    return
        <popular_item>
            { $item/itemno }
            { $item/description }
            <bid_count>{ $bc/nbids/text() }</bid_count>
        </popular_item>
 }
</result>

Expected output

 1 <result>
 2     <popular_item>
 3         <itemno>1001</itemno>
 4         <description>Red Bicycle</description>
 5         <bid_count>5</bid_count>
 6     </popular_item>
 7     <popular_item>
 8         <itemno>1002</itemno>
 9         <description>Motorcycle</description>
10         <bid_count>5</bid_count>
11     </popular_item>
12 </result>

RDB - Q13

[Table of contents][Back to home page]

For each user who has placed a bid, give the userid, name, number of bids, and average bid, in order by userid.

magic/xml solution

 1 users = XML.load('users.xml')
 2 bids  = XML.load('bids.xml')
 3 
 4 XML.result! {
 5     bids.descendants(:userid).map{|uid| uid.text}.uniq.sort.each{|uid|
 6         users.each({:@userid => uid}){|u|
 7             user_bids = bids.find_all{|b| b.is_a? XML and b[:@userid] == uid}
 8             bidder! {
 9                 add! u.child(:userid)
10                 add! u.child(:name)
11                 bidcount! user_bids.size
12                 sum = 0.0
13                 user_bids.each{|b|
14                     sum += b[:@bid].to_i
15                 }
16                 a = sum / user_bids.size
17 a = a.to_i if a.to_i == a
18                 avgbid! a
19             }
20         }
21     }
22 }

XQuery solution

<result>
 {
    for $uid in distinct-values(doc("bids.xml")//userid),
        $u in doc("users.xml")//user_tuple[userid = $uid]
    let $b := doc("bids.xml")//bid_tuple[userid = $uid]
    order by $u/userid
    return
        <bidder>
            { $u/userid }
            { $u/name }
            <bidcount>{ count($b) }</bidcount>
            <avgbid>{ avg($b/bid) }</avgbid>
        </bidder>
  }
</result>

Expected output

 1 <result>
 2     <bidder>
 3         <userid>U01</userid>
 4         <name>Tom Jones</name>
 5         <bidcount>2</bidcount>
 6         <avgbid>220</avgbid>
 7     </bidder>
 8     <bidder>
 9         <userid>U02</userid>
10         <name>Mary Doe</name>
11         <bidcount>5</bidcount>
12         <avgbid>387</avgbid>
13     </bidder>
14     <bidder>
15         <userid>U03</userid>
16         <name>Dee Linquent</name>
17         <bidcount>2</bidcount>
18         <avgbid>487.5</avgbid>
19     </bidder>
20     <bidder>
21         <userid>U04</userid>
22         <name>Roger Smith</name>
23         <bidcount>5</bidcount>
24         <avgbid>266</avgbid>
25     </bidder>
26     <bidder>
27         <userid>U05</userid>
28         <name>Jack Sprat</name>
29         <bidcount>2</bidcount>
30         <avgbid>110</avgbid>
31     </bidder>
32 </result>

RDB - Q14

[Table of contents][Back to home page]

List item numbers and average bids for items that have received three or more bids, in descending order by average bid.

magic/xml solution

 1 bids = XML.load('bids.xml').children(:bid_tuple)
 2 
 3 XML.result! {
 4     bids_of_item = Hash.new([])
 5     sum_bids_of_item = Hash.new(0.0)
 6     bids.each{|b|
 7         i = b[:@itemno]
 8         bids_of_item[i] += [b]
 9         sum_bids_of_item[i] += b[:@bid].to_i
10     }
11     bids_of_item.find_all{|i,b| b.size >= 3}.map{|i,b| [sum_bids_of_item[i] / b.size, i, b]}.sort.reverse.each{|a,i,b|
12         popular_item! {
13             itemno! i
14 a = a.to_i if a.to_i == a
15             avgbid! a
16         }
17     
18     }
19 }

XQuery solution

<result>
 {
    for $i in distinct-values(doc("bids.xml")//itemno)
    let $b := doc("bids.xml")//bid_tuple[itemno = $i]
    let $avgbid := avg($b/bid)
    where count($b) >= 3
    order by $avgbid descending
    return
        <popular_item>
            <itemno>{ $i }</itemno>
            <avgbid>{ $avgbid }</avgbid>
        </popular_item>
  }
</result>

Expected output

 1 <result>
 2     <popular_item>
 3         <itemno>1002</itemno>
 4         <avgbid>800</avgbid>
 5     </popular_item>
 6     <popular_item>
 7         <itemno>1007</itemno>
 8         <avgbid>200</avgbid>
 9     </popular_item>
10     <popular_item>
11         <itemno>1001</itemno>
12         <avgbid>45</avgbid>
13     </popular_item>
14 </result>

RDB - Q15

[Table of contents][Back to home page]

List names of users who have placed multiple bids of at least $100 each.

magic/xml solution

 1 users = XML.load('users.xml')
 2 bids  = XML.load('bids.xml')
 3 
 4 XML.result! {
 5     users.each(XML){|u|
 6         next unless bids.find_all{|b| b.is_a? XML and b[:@userid] == u[:@userid] and b[:@bid].to_i >= 100 }.size > 1
 7         big_spender! u[:@name]
 8     }
 9 }

XQuery solution

<result>
  {
    for $u in doc("users.xml")//user_tuple
    let $b := doc("bids.xml")//bid_tuple[userid=$u/userid and bid>=100]
    where count($b) > 1
    return
        <big_spender>{ $u/name/text() }</big_spender>
  }
</result>

Expected output

1 <result>
2     <big_spender>Mary Doe</big_spender>
3     <big_spender>Dee Linquent</big_spender>
4     <big_spender>Roger Smith</big_spender>
5 </result>

RDB - Q16

[Table of contents][Back to home page]

List all registered users in order by userid; for each user, include the userid, name, and an indication of whether the user is active (has at least one bid on record) or inactive (has no bid on record).

magic/xml solution

 1 users = XML.load('users.xml').sort_by{|i| i[:@userid].to_i}
 2 bids  = XML.load('bids.xml')
 3 
 4 XML.result! {
 5     users.each(XML){|u|
 6         user_bids = bids.children({:@userid => u[:@userid]})
 7         user! {
 8             add! u.child(:userid)
 9             add! u.child(:name)
10             status! (user_bids.empty? ? 'inactive' : 'active')
11         }
12     }
13 }

XQuery solution

<result>
  {
    for $u in doc("users.xml")//user_tuple
    let $b := doc("bids.xml")//bid_tuple[userid = $u/userid]
    order by $u/userid
    return
        <user>
            { $u/userid }
            { $u/name }
            {
                if (empty($b))
                  then <status>inactive</status>
                  else <status>active</status>
            }
        </user>
  }
</result>

Expected output

 1 
 2 
 3 <result>
 4     <user>
 5         <userid>U01</userid>
 6         <name>Tom Jones</name>
 7         <status>active</status>
 8     </user>
 9     <user>
10         <userid>U02</userid>
11         <name>Mary Doe</name>
12         <status>active</status>
13     </user>
14     <user>
15         <userid>U03</userid>
16         <name>Dee Linquent</name>
17         <status>active</status>
18     </user>
19     <user>
20         <userid>U04</userid>
21         <name>Roger Smith</name>
22         <status>active</status>
23     </user>
24     <user>
25         <userid>U05</userid>
26         <name>Jack Sprat</name>
27         <status>active</status>
28     </user>
29     <user>
30         <userid>U06</userid>
31         <name>Rip Van Winkle</name>
32         <status>inactive</status>
33     </user>
34 </result>
35 

RDB - Q17

[Table of contents][Back to home page]

List the names of users, if any, who have bid on every item.

magic/xml solution

 1 users = XML.load('users.xml')
 2 items = XML.load('items.xml')
 3 bids  = XML.load('bids.xml')
 4 
 5 XML.frequent_bidder! {
 6     users.each(XML){|u|
 7         next unless items.all?{|item|
 8             (!item.is_a? XML) or
 9             bids.any?{|b| b.is_a? XML and item[:@itemno] == b[:@itemno] and u[:@userid] == b[:@userid]}
10         }
11         add! u.child(:name)
12     }
13 }

XQuery solution

<frequent_bidder>
  {
    for $u in doc("users.xml")//user_tuple
    where 
      every $item in doc("items.xml")//item_tuple satisfies 
        some $b in doc("bids.xml")//bid_tuple satisfies 
          ($item/itemno = $b/itemno and $u/userid = $b/userid)
    return
        $u/name
  }
</frequent_bidder>

Expected output

1 <frequent_bidder />

RDB - Q18

[Table of contents][Back to home page]

List all users in alphabetic order by name. For each user, include descriptions of all the items (if any) that were bid on by that user, in alphabetic order.

magic/xml solution

 1 users = XML.load('users.xml').children(:user_tuple).sort_by{|i| i[:@name]}
 2 items = XML.load('items.xml')
 3 bids  = XML.load('bids.xml')
 4 
 5 XML.result! {
 6     users.each{|u|
 7         user! {
 8             add! u.child(:name)
 9             bids.find_all{|b|
10                 b.is_a? XML and b[:@userid] == u[:@userid]
11             }.map{|b| b[:@itemno]}.uniq.map{|b|
12                 items.find{|i| i.is_a? XML and i[:@itemno] == b}[:@description]
13             }.sort.each{|dsc|
14                 bid_on_item! dsc
15             }
16         }
17     }
18 }

XQuery solution

<result>
  {
    for $u in doc("users.xml")//user_tuple
    order by $u/name
    return
        <user>
            { $u/name }
            {
                for $b in distinct-values(doc("bids.xml")//bid_tuple
                                             [userid = $u/userid]/itemno)
                for $i in doc("items.xml")//item_tuple[itemno = $b]
                let $descr := $i/description/text()
                order by $descr
                return
                    <bid_on_item>{ $descr }</bid_on_item>
            }
        </user>
  }
</result>

Expected output

 1 <result>
 2     <user>
 3         <name>Dee Linquent</name>
 4         <bid_on_item>Motorcycle</bid_on_item>
 5         <bid_on_item>Racing Bicycle</bid_on_item>
 6     </user>
 7     <user>
 8         <name>Jack Sprat</name>
 9         <bid_on_item>Old Bicycle</bid_on_item>
10         <bid_on_item>Racing Bicycle</bid_on_item>
11     </user>
12     <user>
13         <name>Mary Doe</name>
14         <bid_on_item>Motorcycle</bid_on_item>
15         <bid_on_item>Red Bicycle</bid_on_item>
16     </user>
17     <user>
18         <name>Rip Van Winkle</name>
19     </user>
20     <user>
21         <name>Roger Smith</name>
22         <bid_on_item>Motorcycle</bid_on_item>
23         <bid_on_item>Old Bicycle</bid_on_item>
24         <bid_on_item>Racing Bicycle</bid_on_item>
25         <bid_on_item>Red Bicycle</bid_on_item>
26     </user>
27     <user>
28         <name>Tom Jones</name>
29         <bid_on_item>Motorcycle</bid_on_item>
30         <bid_on_item>Tricycle</bid_on_item>
31     </user>
32 </result>

Input for SEQ - report1.xml

[Table of contents][Back to home page]
 1 <report>
 2   <section>
 3     <section.title>Procedure</section.title>
 4      <section.content>
 5       The patient was taken to the operating room where she was placed
 6       in supine position and
 7       <anesthesia>induced under general anesthesia.</anesthesia>
 8       <prep> 
 9         <action>A Foley catheter was placed to decompress the bladder</action>
10         and the abdomen was then prepped and draped in sterile fashion.
11       </prep>  
12       <incision>
13         A curvilinear incision was made
14         <geography>in the midline immediately infraumbilical</geography>
15         and the subcutaneous tissue was divided
16         <instrument>using electrocautery.</instrument>
17       </incision>
18       The fascia was identified and
19       <action>#2 0 Maxon stay sutures were placed on each side of the midline.
20       </action>
21       <incision>
22         The fascia was divided using
23         <instrument>electrocautery</instrument>
24         and the peritoneum was entered.
25       </incision>
26       <observation>The small bowel was identified.</observation>
27       and
28       <action>
29         the
30         <instrument>Hasson trocar</instrument>
31         was placed under direct visualization.
32       </action>
33       <action>
34         The
35         <instrument>trocar</instrument>
36         was secured to the fascia using the stay sutures.
37       </action>
38      </section.content>
39   </section>
40 </report>

SEQ - Q1

[Table of contents][Back to home page]

In the Procedure section of Report1, what Instruments were used in the second Incision?

magic/xml solution

1 XML.load('report1.xml').descendants(:section) {|s|
2     print s.descendants(:incision)[1].child(:instrument) if s[:"@section.title"] == "Procedure"
3 }

XQuery solution

for $s in doc("report1.xml")//section[section.title = "Procedure"]
return ($s//incision)[2]/instrument

Expected output

1 <instrument>electrocautery</instrument>

SEQ - Q2

[Table of contents][Back to home page]

In the Procedure section of Report1, what are the first two Instruments to be used?

magic/xml solution

1 XML.load('report1.xml').descendants(:section) {|s|
2     print s.descendants(:instrument)[0,2] if s[:"@section.title"] == "Procedure"
3 }

XQuery solution

for $s in doc("report1.xml")//section[section.title = "Procedure"]
return ($s//instrument)[position()<=2]

Expected output

1 <instrument>using electrocautery.</instrument>
2 <instrument>electrocautery</instrument>

SEQ - Q3

[Table of contents][Back to home page]

In Report1, what Instruments were used in the first two Actions after the second Incision?

magic/xml solution

1 doc = XML.load('report1.xml')
2 i2 = doc.descendants(:incision)[1]
3 
4 print doc.range(i2,nil).descendants(:action)[0,2].children(:instrument)

XQuery solution

let $i2 := (doc("report1.xml")//incision)[2]
for $a in (doc("report1.xml")//action)[. >> $i2][position()<=2]
return $a//instrument

Expected output

1 <instrument>Hasson trocar</instrument>
2 <instrument>trocar</instrument>

SEQ - Q4

[Table of contents][Back to home page]

In Report1, find "Procedure" sections where no Anesthesia element occurs before the first Incision

magic/xml solution

1 XML.load('report1.xml').descendants(:section) {|p|
2     next unless p[:"@section.title"] == "Procedure"
3     i1 = p.descendants(:incision)[0]
4     print p if p.range(nil,i1).descendants(:anesthesia).size == 0
5 }

XQuery solution

for $p in doc("report1.xml")//section[section.title = "Procedure"]
where not(some $a in $p//anesthesia satisfies
        $a << ($p//incision)[1] )
return $p

Expected output

1 

SEQ - Q5

[Table of contents][Back to home page]

In Report1, what happened between the first Incision and the second Incision?

magic/xml solution

1 XML.critical_sequence! {
2    p = XML.load('report1.xml').descendants(:section).find {|p| p[:"@section.title"] == "Procedure"}
3    i1,i2, = *p.descendants(:incision)
4 add! p.subsequence(i1,i2).map{|p| [p] + [p].descendants}
5 }

XQuery solution

<critical_sequence>
 {
  let $proc := doc("report1.xml")//section[section.title="Procedure"][1],
      $i1 :=  ($proc//incision)[1],
      $i2 :=  ($proc//incision)[2]
  for $n in $proc//node() except $i1//node()
  where $n >> $i1 and $n << $i2
  return $n 
 }
</critical_sequence>

Expected output

1 <critical_sequence>
2       The fascia was identified and
3       <action>#2 0 Maxon stay sutures were placed on each side of the midline.
4       </action>#2 0 Maxon stay sutures were placed on each side of the midline.
5 </critical_sequence>

Input for SGML - sgml.xml

[Table of contents][Back to home page]
  1 <!DOCTYPE report SYSTEM "report.dtd">
  2 <report>
  3 <title>Getting started with SGML</title>
  4 <chapter>
  5 <title>The business challenge</title>
  6 <intro>
  7 <para>With the ever-changing and growing global market, companies and
  8 large organizations are searching for ways to become more viable and
  9 competitive. Downsizing and other cost-cutting measures demand more
 10 efficient use of corporate resources. One very important resource is
 11 an organization's information.</para>
 12 <para>As part of the move toward integrated information management,
 13 whole industries are developing and implementing standards for
 14 exchanging technical information. This report describes how one such
 15 standard, the Standard Generalized Markup Language (SGML), works as
 16 part of an overall information management strategy.</para>
 17 <graphic graphname="infoflow"/></intro></chapter>
 18 <chapter>
 19 <title>Getting to know SGML</title>
 20 <intro>
 21 <para>While SGML is a fairly recent technology, the use of
 22 <emph>markup</emph> in computer-generated documents has existed for a
 23 while.</para></intro>
 24 <section shorttitle="What is markup?">
 25 <title>What is markup, or everything you always wanted to know about
 26 document preparation but were afraid to ask?</title>
 27 <intro>
 28 <para>Markup is everything in a document that is not content. The
 29 traditional meaning of markup is the manual <emph>marking</emph> up
 30 of typewritten text to give instructions for a typesetter or
 31 compositor about how to fit the text on a page and what typefaces to
 32 use. This kind of markup is known as <emph>procedural markup</emph>.</para></intro>
 33 <topic topicid="top1">
 34 <title>Procedural markup</title>
 35 <para>Most electronic publishing systems today use some form of
 36 procedural markup. Procedural markup codes are good for one
 37 presentation of the information.</para></topic>
 38 <topic topicid="top2">
 39 <title>Generic markup</title>
 40 <para>Generic markup (also known as descriptive markup) describes the
 41 <emph>purpose</emph> of the text in a document. A basic concept of
 42 generic markup is that the content of a document must be separate from
 43 the style. Generic markup allows for multiple presentations of the
 44 information.</para></topic>
 45 <topic topicid="top3">
 46 <title>Drawbacks of procedural markup</title>
 47 <para>Industries involved in technical documentation increasingly
 48 prefer generic over procedural markup schemes. When a company changes
 49 software or hardware systems, enormous data translation tasks arise,
 50 often resulting in errors.</para></topic></section>
 51 <section shorttitle="What is SGML?">
 52 <title>What <emph>is</emph> SGML in the grand scheme of the universe, anyway?</title>
 53 <intro>
 54 <para>SGML defines a strict markup scheme with a syntax for defining
 55 document data elements and an overall framework for marking up
 56 documents.</para>
 57 <para>SGML can describe and create documents that are not dependent on
 58 any hardware, software, formatter, or operating system. Since SGML documents
 59 conform to an international standard, they are portable.</para></intro></section>
 60 <section shorttitle="How does SGML work?">
 61 <title>How is SGML and would you recommend it to your grandmother?</title>
 62 <intro>
 63 <para>You can break a typical document into three layers: structure,
 64 content, and style. SGML works by separating these three aspects and
 65 deals mainly with the relationship between structure and content.</para></intro>
 66 <topic topicid="top4">
 67 <title>Structure</title>
 68 <para>At the heart of an SGML application is a file called the DTD, or
 69 Document Type Definition. The DTD sets up the structure of a document,
 70 much like a database schema describes the types of information it
 71 handles.</para>
 72 <para>A database schema also defines the relationships between the
 73 various types of data. Similarly, a DTD specifies <emph>rules</emph>
 74 to help ensure documents have a consistent, logical structure.</para></topic>
 75 <topic topicid="top5">
 76 <title>Content</title>
 77 <para>Content is the information itself. The method for identifying
 78 the information and its meaning within this framework is called
 79 <emph>tagging</emph>. Tagging must
 80 conform to the rules established in the DTD (see <xref xrefid="top4"/>).</para>
 81 <graphic graphname="tagexamp"/></topic>
 82 <topic topicid="top6">
 83 <title>Style</title>
 84 <para>SGML does not standardize style or other processing methods for
 85 information stored in SGML.</para></topic></section></chapter>
 86 <chapter>
 87 <title>Resources</title>
 88 <section>
 89 <title>Conferences, tutorials, and training</title>
 90 <intro>
 91 <para>The Graphic Communications Association has been
 92 instrumental in the development of SGML. GCA provides conferences,
 93 tutorials, newsletters, and publication sales for both members and
 94 non-members.</para>
 95 <para security="c">Exiled members of the former Soviet Union's secret
 96 police, the KGB, have infiltrated the upper ranks of the GCA and are
 97 planning the Final Revolution as soon as DSSSL is completed.</para>
 98 </intro>
 99 </section>
100 </chapter>
101 </report>

SGML - Q1

[Table of contents][Back to home page]

Locate all paragraphs in the report (all "para" elements occurring anywhere within the "report" element).

magic/xml solution

1 XML.result!(XML.load('sgml.xml').descendants(:para))

XQuery solution

<result>
  { 
    doc("sgml.xml")//report//para 
  }
</result>

Expected output

 1 <result><para>With the ever-changing and growing global market, companies and
 2 large organizations are searching for ways to become more viable and
 3 competitive. Downsizing and other cost-cutting measures demand more
 4 efficient use of corporate resources. One very important resource is
 5 an organization's information.</para><para>As part of the move toward integrated information management,
 6 whole industries are developing and implementing standards for
 7 exchanging technical information. This report describes how one such
 8 standard, the Standard Generalized Markup Language (SGML), works as
 9 part of an overall information management strategy.</para><para>While SGML is a fairly recent technology, the use of
10 <emph>markup</emph> in computer-generated documents has existed for a
11 while.</para><para>Markup is everything in a document that is not content. The
12 traditional meaning of markup is the manual <emph>marking</emph> up
13 of typewritten text to give instructions for a typesetter or
14 compositor about how to fit the text on a page and what typefaces to
15 use. This kind of markup is known as <emph>procedural markup</emph>.</para><para>Most electronic publishing systems today use some form of
16 procedural markup. Procedural markup codes are good for one
17 presentation of the information.</para><para>Generic markup (also known as descriptive markup) describes the
18 <emph>purpose</emph> of the text in a document. A basic concept of
19 generic markup is that the content of a document must be separate from
20 the style. Generic markup allows for multiple presentations of the
21 information.</para><para>Industries involved in technical documentation increasingly
22 prefer generic over procedural markup schemes. When a company changes
23 software or hardware systems, enormous data translation tasks arise,
24 often resulting in errors.</para><para>SGML defines a strict markup scheme with a syntax for defining
25 document data elements and an overall framework for marking up
26 documents.</para><para>SGML can describe and create documents that are not dependent on
27 any hardware, software, formatter, or operating system. Since SGML documents
28 conform to an international standard, they are portable.</para><para>You can break a typical document into three layers: structure,
29 content, and style. SGML works by separating these three aspects and
30 deals mainly with the relationship between structure and content.</para><para>At the heart of an SGML application is a file called the DTD, or
31 Document Type Definition. The DTD sets up the structure of a document,
32 much like a database schema describes the types of information it
33 handles.</para><para>A database schema also defines the relationships between the
34 various types of data. Similarly, a DTD specifies <emph>rules</emph>
35 to help ensure documents have a consistent, logical structure.</para><para>Content is the information itself. The method for identifying
36 the information and its meaning within this framework is called
37 <emph>tagging</emph>. Tagging must
38 conform to the rules established in the DTD (see <xref xrefid='top4'/>).</para><para>SGML does not standardize style or other processing methods for
39 information stored in SGML.</para><para>The Graphic Communications Association has been
40 instrumental in the development of SGML. GCA provides conferences,
41 tutorials, newsletters, and publication sales for both members and
42 non-members.</para><para security='c'>Exiled members of the former Soviet Union's secret
43 police, the KGB, have infiltrated the upper ranks of the GCA and are
44 planning the Final Revolution as soon as DSSSL is completed.</para></result>

SGML - Q2

[Table of contents][Back to home page]

Locate all paragraph elements in an introduction (all "para" elements directly contained within an "intro" element).

magic/xml solution

1 puts XML.result(XML.load('sgml.xml').descendants(:intro, :para))

XQuery solution

<result>
  { 
    doc("sgml.xml")//intro/para 
  }
</result>

Expected output

 1 <result><para>With the ever-changing and growing global market, companies and
 2 large organizations are searching for ways to become more viable and
 3 competitive. Downsizing and other cost-cutting measures demand more
 4 efficient use of corporate resources. One very important resource is
 5 an organization's information.</para><para>As part of the move toward integrated information management,
 6 whole industries are developing and implementing standards for
 7 exchanging technical information. This report describes how one such
 8 standard, the Standard Generalized Markup Language (SGML), works as
 9 part of an overall information management strategy.</para><para>While SGML is a fairly recent technology, the use of
10 <emph>markup</emph> in computer-generated documents has existed for a
11 while.</para><para>Markup is everything in a document that is not content. The
12 traditional meaning of markup is the manual <emph>marking</emph> up
13 of typewritten text to give instructions for a typesetter or
14 compositor about how to fit the text on a page and what typefaces to
15 use. This kind of markup is known as <emph>procedural markup</emph>.</para><para>SGML defines a strict markup scheme with a syntax for defining
16 document data elements and an overall framework for marking up
17 documents.</para><para>SGML can describe and create documents that are not dependent on
18 any hardware, software, formatter, or operating system. Since SGML documents
19 conform to an international standard, they are portable.</para><para>You can break a typical document into three layers: structure,
20 content, and style. SGML works by separating these three aspects and
21 deals mainly with the relationship between structure and content.</para><para>The Graphic Communications Association has been
22 instrumental in the development of SGML. GCA provides conferences,
23 tutorials, newsletters, and publication sales for both members and
24 non-members.</para><para security='c'>Exiled members of the former Soviet Union's secret
25 police, the KGB, have infiltrated the upper ranks of the GCA and are
26 planning the Final Revolution as soon as DSSSL is completed.</para></result>

SGML - Q3

[Table of contents][Back to home page]

Locate all paragraphs in the introduction of a section that is in a chapter that has no introduction (all "para" elements directly contained within an "intro" element directly contained in a "section" element directly contained in a "chapter" element. The "chapter" element must not directly contain an "intro" element).

magic/xml solution

1 XML.result! {
2     XML.load('sgml.xml').descendants(:chapter) {|c|
3         next unless c.children(:intro).empty?
4         add! c.children(:section, :intro, :para)
5     }
6 }

XQuery solution

<result>
  {
    for $c in doc("sgml.xml")//chapter
    where empty($c/intro)
    return $c/section/intro/para
  }
</result>

Expected output

1 <result><para>The Graphic Communications Association has been
2 instrumental in the development of SGML. GCA provides conferences,
3 tutorials, newsletters, and publication sales for both members and
4 non-members.</para><para security='c'>Exiled members of the former Soviet Union's secret
5 police, the KGB, have infiltrated the upper ranks of the GCA and are
6 planning the Final Revolution as soon as DSSSL is completed.</para></result>

SGML - Q4

[Table of contents][Back to home page]

Locate the second paragraph in the third section in the second chapter (the second "para" element occurring in the third "section" element occurring in the second "chapter" element occurring in the "report").

magic/xml solution

1 XML.result!(
2     XML.load('sgml.xml').descendants(:chapter)[1].descendants(:section)[2].descendants(:para)[1]
3 )

XQuery solution

<result>
  {
    (((doc("sgml.xml")//chapter)[2]//section)[3]//para)[2]
  }
</result>

Expected output

1 <result><para>At the heart of an SGML application is a file called the DTD, or
2 Document Type Definition. The DTD sets up the structure of a document,
3 much like a database schema describes the types of information it
4 handles.</para></result>

SGML - Q5

[Table of contents][Back to home page]

Locate all classified paragraphs (all "para" elements whose "security" attribute has the value "c").

magic/xml solution

1 XML.result!(XML.load('sgml.xml').descendants(:para).find_all{|p| p[:security] == 'c'})

XQuery solution

<result>
  {
    doc("sgml.xml")//para[@security = "c"]
  }
</result> 

Expected output

1 <result><para security='c'>Exiled members of the former Soviet Union's secret
2 police, the KGB, have infiltrated the upper ranks of the GCA and are
3 planning the Final Revolution as soon as DSSSL is completed.</para></result>

SGML - Q6

[Table of contents][Back to home page]

List the short titles of all sections (the values of the "shorttitle" attributes of all "section" elements, expressing each short title as the value of a new element.)

magic/xml solution

1 XML.result! {
2     XML.load('sgml.xml').descendants(:section).each{|s|
3         stitle! s[:shorttitle]
4     }
5 }

XQuery solution

<result>
  {
    for $s in doc("sgml.xml")//section/@shorttitle
    return <stitle>{ $s }</stitle>
  }
</result>

Expected output

1 <result><stitle>What is markup?</stitle><stitle>What is SGML?</stitle><stitle>How does SGML work?</stitle><stitle/></result>

SGML - Q7

[Table of contents][Back to home page]

Locate the initial letter of the initial paragraph of all introductions (the first character in the content [character content as well as element content] of the first "para" element contained in an "intro" element).

magic/xml solution

1 XML.result! {
2     XML.load('sgml.xml').descendants(:intro) {|i|
3         first_letter! i.children(:para)[0].text[0,1]
4     }
5 }

XQuery solution

<result>
  {
    for $i in doc("sgml.xml")//intro/para[1]
    return
        <first_letter>{ substring(string($i), 1, 1) }</first_letter>
  }
</result>

Expected output

1 <result><first_letter>W</first_letter><first_letter>W</first_letter><first_letter>M</first_letter><first_letter>S</first_letter><first_letter>Y</first_letter><first_letter>T</first_letter></result>

SGML - Q8a

[Table of contents][Back to home page]

Locate all sections with a title that has "is SGML" in it. The string may occur anywhere in the descendants of the title element, and markup boundaries are ignored.

magic/xml solution

1 XML.result! {
2     XML.load('sgml.xml').descendants(:section) {|s|
3         add! s if s.descendants(:title).any?{|t| t =~ /is SGML/}
4     }
5 }

XQuery solution

<result>
   {
     doc("sgml.xml")//section[.//title[contains(., "is SGML")]]
   }
</result>

Expected output

 1 <result><section shorttitle='What is SGML?'>
 2 <title>What <emph>is</emph> SGML in the grand scheme of the universe, anyway?</title>
 3 <intro>
 4 <para>SGML defines a strict markup scheme with a syntax for defining
 5 document data elements and an overall framework for marking up
 6 documents.</para>
 7 <para>SGML can describe and create documents that are not dependent on
 8 any hardware, software, formatter, or operating system. Since SGML documents
 9 conform to an international standard, they are portable.</para></intro></section><section shorttitle='How does SGML work?'>
10 <title>How is SGML and would you recommend it to your grandmother?</title>
11 <intro>
12 <para>You can break a typical document into three layers: structure,
13 content, and style. SGML works by separating these three aspects and
14 deals mainly with the relationship between structure and content.</para></intro>
15 <topic topicid='top4'>
16 <title>Structure</title>
17 <para>At the heart of an SGML application is a file called the DTD, or
18 Document Type Definition. The DTD sets up the structure of a document,
19 much like a database schema describes the types of information it
20 handles.</para>
21 <para>A database schema also defines the relationships between the
22 various types of data. Similarly, a DTD specifies <emph>rules</emph>
23 to help ensure documents have a consistent, logical structure.</para></topic>
24 <topic topicid='top5'>
25 <title>Content</title>
26 <para>Content is the information itself. The method for identifying
27 the information and its meaning within this framework is called
28 <emph>tagging</emph>. Tagging must
29 conform to the rules established in the DTD (see <xref xrefid='top4'/>).</para>
30 <graphic graphname='tagexamp'/></topic>
31 <topic topicid='top6'>
32 <title>Style</title>
33 <para>SGML does not standardize style or other processing methods for
34 information stored in SGML.</para></topic></section></result>

SGML - Q8b

[Table of contents][Back to home page]

Same as (Q8a), but the string "is SGML" cannot be interrupted by sub-elements, and must appear in a single text node.

magic/xml solution

 1 XML.result! {
 2     doc = XML.load('sgml.xml')
 3 doc.normalize!
 4     doc.descendants(:section) {|s|
 5         add! s if s.descendants(:title).any?{|t|
 6             t.descendants.any?{|d| d.is_a? String and d =~ /is SGML/}
 7         }
 8     }
 9 }

XQuery solution

<result>
   {
     doc("sgml.xml")//section[.//title/text()[contains(., "is SGML")]]
   }
</result>

Expected output

 1 <result><section shorttitle='How does SGML work?'>
 2 <title>How is SGML and would you recommend it to your grandmother?</title>
 3 <intro>
 4 <para>You can break a typical document into three layers: structure,
 5 content, and style. SGML works by separating these three aspects and
 6 deals mainly with the relationship between structure and content.</para></intro>
 7 <topic topicid='top4'>
 8 <title>Structure</title>
 9 <para>At the heart of an SGML application is a file called the DTD, or
10 Document Type Definition. The DTD sets up the structure of a document,
11 much like a database schema describes the types of information it
12 handles.</para>
13 <para>A database schema also defines the relationships between the
14 various types of data. Similarly, a DTD specifies <emph>rules</emph>
15 to help ensure documents have a consistent, logical structure.</para></topic>
16 <topic topicid='top5'>
17 <title>Content</title>
18 <para>Content is the information itself. The method for identifying
19 the information and its meaning within this framework is called
20 <emph>tagging</emph>. Tagging must
21 conform to the rules established in the DTD (see <xref xrefid='top4'/>).</para>
22 <graphic graphname='tagexamp'/></topic>
23 <topic topicid='top6'>
24 <title>Style</title>
25 <para>SGML does not standardize style or other processing methods for
26 information stored in SGML.</para></topic></section></result>

SGML - Q9

[Table of contents][Back to home page]

Locate all the topics referenced by a cross-reference anywhere in the report (all the "topic" elements whose "topicid" attribute value is the same as an "xrefid" attribute value of any "xref" element).

magic/xml solution

1 doc = XML.load('sgml.xml')
2 
3 XML.result! {
4     doc.descendants(:xref) {|xref|
5         add! doc.descendants(:topic).find_all{|t| t[:topicid] == xref[:xrefid]}
6     }
7 }

XQuery solution

<result>
  {
    for $id in doc("sgml.xml")//xref/@xrefid
    return doc("sgml.xml")//topic[@topicid = $id]
  }
</result>

Expected output

 1 <result><topic topicid='top4'>
 2 <title>Structure</title>
 3 <para>At the heart of an SGML application is a file called the DTD, or
 4 Document Type Definition. The DTD sets up the structure of a document,
 5 much like a database schema describes the types of information it
 6 handles.</para>
 7 <para>A database schema also defines the relationships between the
 8 various types of data. Similarly, a DTD specifies <emph>rules</emph>
 9 to help ensure documents have a consistent, logical structure.</para></topic></result>

SGML - Q10

[Table of contents][Back to home page]

Locate the closest title preceding the cross-reference ("xref") element whose "xrefid" attribute is "top4" (the "title" element that would be touched last before this "xref" element when touching each element in document order).

magic/xml solution

1 doc = XML.load('sgml.xml')
2 
3 XML.result! {
4     xref = doc.descendants(:xref).find{|xref| xref[:xrefid] == "top4"}
5     add! doc.range(nil,xref).descendants(:title)[-1]
6 }

XQuery solution

<result>
  {
    let $x := doc("sgml.xml")//xref[@xrefid = "top4"],
        $t := doc("sgml.xml")//title[. << $x]
    return $t[last()]
  }
</result>

Expected output

1 <result><title>Content</title></result>

Input for STRING - company-data.xml

[Table of contents][Back to home page]
 1 <?xml version="1.0" encoding="ISO-8859-1"?> 
 2 <!DOCTYPE company SYSTEM "company.dtd">
 3 <company>
 4    <name>Foobar Corporation</name>
 5    <ticker_symbol>FOO</ticker_symbol>
 6 
 7    <description>Foobar Corporation is a maker of Foo(TM) and
 8         Foobar(TM) products and a leading software company with a 300
 9         Billion dollar revenue in 1999. It is located in Alaska.
10    </description>
11 
12    <business_code>Software</business_code>
13    <partners>
14         <partner>YouNameItWeIntegrateIt.com</partner>
15         <partner>TheAppCompany Inc.</partner>
16    </partners>
17    <competitors>
18         <competitor>Gorilla Corporation</competitor>
19    </competitors>
20 </company>

Input for STRING - string.xml

[Table of contents][Back to home page]
 1 <?xml version="1.0" encoding="ISO-8859-1"?>
 2 <news>
 3 <news_item>
 4    <title> Gorilla Corporation acquires YouNameItWeIntegrateIt.com </title>
 5    <content>
 6       <par> Today, Gorilla Corporation announced that it will purchase
 7           YouNameItWeIntegrateIt.com. The shares of
 8           YouNameItWeIntegrateIt.com dropped $3.00 as a result of this
 9           announcement.
10       </par>
11 
12       <par> As a result of this acquisition, the CEO of
13           YouNameItWeIntegrateIt.com Bill Smarts resigned. He did not
14           announce what he will do next.  Sources close to
15           YouNameItWeIntegrateIt.com hint that Bill Smarts might be
16           taking a position in Foobar Corporation.
17       </par>
18 
19       <par>YouNameItWeIntegrateIt.com is a leading systems integrator
20           that enables <quote>brick and mortar</quote> companies to
21           have a presence on the web.
22       </par>
23 
24    </content>
25    <date>1-20-2000</date>
26    <author>Mark Davis</author>
27    <news_agent>News Online</news_agent>
28 </news_item>
29 
30 <news_item>
31    <title>Foobar Corporation releases its new line of Foo products
32    today</title>
33    <content>
34       <par> Foobar Corporation releases the 20.9 version of its Foo
35             products.  The new version of Foo products solve known
36             performance problems which existed in 20.8 line and
37             increases the speed of Foo based products tenfold. It also
38             allows wireless clients to be connected to the Foobar
39             servers.
40       </par>
41       <par> The President of Foobar Corporation announced that they
42             were proud to release 20.9 version of Foo products and
43             they will upgrade existing customers <footnote>where
44             service agreements exist</footnote>
45             promptly. TheAppCompany Inc. immediately announced that it
46             will release the new version of its products to utilize
47             the 20.9 architecture within the next three months.
48       </par>
49       <figure>
50           <title>Presidents of Foobar Corporation and TheAppCompany
51           Inc. Shake Hands</title> <image source="handshake.jpg"/>
52       </figure>
53    </content>
54    <date>1-20-2000</date>
55    <news_agent>Foobar Corporation</news_agent>
56 </news_item>
57 
58 <news_item> <title>Foobar Corporation is suing Gorilla Corporation for
59    patent infringement </title>
60    <content>
61       <par> In surprising developments today, Foobar Corporation
62          announced that it is suing Gorilla Corporation for patent
63          infringement. The patents that were mentioned as part of the
64          lawsuit are considered to be the basis of Foobar
65          Corporation's <quote>Wireless Foo</quote> line of products.
66       </par>
67       <par>The tension between Foobar and Gorilla Corporations has
68          been increasing ever since the Gorilla Corporation acquired
69          more than 40 engineers who have left Foobar Corporation,
70          TheAppCompany Inc. and YouNameItWeIntegrateIt.com over the
71          past 3 months. The engineers who have left the Foobar
72          corporation and its partners were rumored to be working on
73          the next generation of server products and applications which
74          will directly compete with Foobar's Foo 20.9 servers. Most of
75          the engineers have relocated to Hawaii where the Gorilla
76          Corporation's server development is located.
77       </par>
78    </content>
79    <date>1-20-2000</date>
80    <news_agent>Reliable News Corporation</news_agent>
81 </news_item>
82 </news>

STRING - Q1

[Table of contents][Back to home page]

Find the titles of all news items where the string "Foobar Corporation" appears in the title.

magic/xml solution

1 XML.load('string.xml').descendants(:news_item, :title).each{|t|
2     print t if t =~ /Foobar Corporation/
3 }

XQuery solution

doc("string.xml")//news_item/title[contains(., "Foobar Corporation")]

Expected output

1 <title>Foobar Corporation releases its new line of Foo
2 products today</title>
3 <title>Foobar Corporation is suing Gorilla Corporation for patent
4 infringement </title>

STRING - Q2

[Table of contents][Back to home page]

Find news items where the Foobar Corporation and one or more of its partners are mentioned in the same paragraph and/or title. List each news item by its title and date.

magic/xml solution

1 partners = XML.load('company-data.xml').descendants(:partner).map{|p| p.text}
2 
3 XML.load('string.xml').descendants(:news_item) {|item|
4     next unless (item.descendants(:title) + item.descendants(:par)).any?{|t|
5        t.text.include? "Foobar Corporation" and partners.any?{|p| t.text.include? p}
6     }
7     XML.news_item!(item.child(:title), item.child(:date))
8 }

XQuery solution

declare function local:partners($company as xs:string) as element()*
{
    let $c := doc("company-data.xml")//company[name = $company]
    return $c//partner
};

let $foobar_partners := local:partners("Foobar Corporation")

for $item in doc("string.xml")//news_item
where
  some $t in $item//title satisfies
    (contains($t/text(), "Foobar Corporation")
    and (some $partner in $foobar_partners satisfies
      contains($t/text(), $partner/text())))
  or (some $par in $item//par satisfies
   (contains(string($par), "Foobar Corporation")
     and (some $partner in $foobar_partners satisfies
        contains(string($par), $partner/text())))) 
return
    <news_item>
        { $item/title }
        { $item/date }
    </news_item>

Expected output

 1 <news_item>
 2     <title> Gorilla Corporation acquires YouNameItWeIntegrateIt.com </title>
 3     <date>1-20-2000</date>
 4 </news_item>
 5 <news_item>
 6     <title>Foobar Corporation releases its new line of Foo products today</title>
 7     <date>1-20-2000</date>
 8 </news_item>
 9 <news_item>
10     <title>Foobar Corporation is suing Gorilla Corporation for patent
11     infringement </title>
12     <date>1-20-2000</date>
13 </news_item>

STRING - Q4

[Table of contents][Back to home page]

Find news items where a company and one of its partners is mentioned in the same news item and the news item is not authored by the company itself.

magic/xml solution

 1 company_data = XML.load('company-data.xml')
 2 partners = company_data.descendants(:partner).map{|p| p.text}
 3 c = company_data[:@name]
 4 
 5 XML.load('string.xml').descendants(:news_item) {|item|
 6     next unless item.text.include? c
 7     next unless partners.any?{|p| item.text.include? p}
 8     next if item[:@news_agent] == c
 9     print item
10 }

XQuery solution

declare function local:partners($company as xs:string) as element()*
{
    let $c := doc("company-data.xml")//company[name = $company]
    return $c//partner
};

for $item in doc("string.xml")//news_item,
    $c in doc("company-data.xml")//company
let $partners := local:partners($c/name)
where contains(string($item), $c/name)
  and (some $p in $partners satisfies
    contains(string($item), $p) and $item/news_agent != $c/name)
return
    $item

Expected output

 1 <news_item>
 2    <title> Gorilla Corporation acquires YouNameItWeIntegrateIt.com </title>
 3    <content>
 4       <par> Today, Gorilla Corporation announced that it will purchase
 5           YouNameItWeIntegrateIt.com. The shares of
 6           YouNameItWeIntegrateIt.com dropped $3.00 as a result of this
 7           announcement.
 8       </par>
 9 
10       <par> As a result of this acquisition, the CEO of
11           YouNameItWeIntegrateIt.com Bill Smarts resigned. He did not
12           announce what he will do next.  Sources close to
13           YouNameItWeIntegrateIt.com hint that Bill Smarts might be
14           taking a position in Foobar Corporation.
15       </par>
16 
17       <par>YouNameItWeIntegrateIt.com is a leading systems integrator
18           that enables <quote>brick and mortar</quote> companies to
19           have a presence on the web.
20       </par>
21 
22    </content>
23    <date>1-20-2000</date>
24    <author>Mark Davis</author>
25    <news_agent>News Online</news_agent>
26 </news_item>
27 <news_item> <title>Foobar Corporation is suing Gorilla Corporation for
28    patent infringement </title>
29    <content>
30       <par> In surprising developments today, Foobar Corporation
31          announced that it is suing Gorilla Corporation for patent
32          infringement. The patents that were mentioned as part of the
33          lawsuit are considered to be the basis of Foobar
34          Corporation's <quote>Wireless Foo</quote> line of products.
35       </par>
36       <par>The tension between Foobar and Gorilla Corporations has
37          been increasing ever since the Gorilla Corporation acquired
38          more than 40 engineers who have left Foobar Corporation,
39          TheAppCompany Inc. and YouNameItWeIntegrateIt.com over the
40          past 3 months. The engineers who have left the Foobar
41          corporation and its partners were rumored to be working on
42          the next generation of server products and applications which
43          will directly compete with Foobar's Foo 20.9 servers. Most of
44          the engineers have relocated to Hawaii where the Gorilla
45          Corporation's server development is located.
46       </par>
47    </content>
48    <date>1-20-2000</date>
49    <news_agent>Reliable News Corporation</news_agent>
50 </news_item>

STRING - Q5

[Table of contents][Back to home page]

For each news item that is relevant to the Gorilla Corporation, create an "item summary" element. The content of the item summary is the content of the title, date, and first paragraph of the news item, separated by periods. A news item is relevant if the name of the company is mentioned anywhere within the content of the news item.

magic/xml solution

 1 XML.load('string.xml').descendants(:news_item) {|item|
 2     next unless item =~ /Gorilla Corporation/
 3     XML.item_summary! {
 4 add! item[:@title].strip
 5         add! ". "
 6         add! item[:@date]
 7         add! ". "
 8         add! item.descendants(:par)[0].text
 9     }
10 }

XQuery solution

for $item in doc("string.xml")//news_item
where contains(string($item/content), "Gorilla Corporation")
return
    <item_summary>
        { concat($item/title,". ") }
        { concat($item/date,". ") }
        { string(($item//par)[1]) }
    </item_summary>

Expected output

 1 <item_summary>Gorilla Corporation acquires
 2 YouNameItWeIntegrateIt.com. 1-20-2000.  Today, Gorilla Corporation
 3 announced that it will purchase YouNameItWeIntegrateIt.com. The shares
 4 of YouNameItWeIntegrateIt.com dropped $3.00 as a result of this
 5 announcement.</item_summary>
 6 
 7 <item_summary>Foobar Corporation is suing Gorilla Corporation for
 8 patent infringement. 1-20-2000.  In surprising developments today,
 9 Foobar Corporation announced that it is suing Gorilla Corporation for
10 patent infringement. The patents that were mentioned as part of the
11 lawsuit are considered to be the basis of Foobar Corporation's
12 Wireless Foo line of products.</item_summary>

Input for TREE - book.xml

[Table of contents][Back to home page]
 1 <?xml version="1.0"?>
 2 <!DOCTYPE book SYSTEM "book.dtd">
 3 <book>
 4   <title>Data on the Web</title>
 5   <author>Serge Abiteboul</author>
 6   <author>Peter Buneman</author>
 7   <author>Dan Suciu</author>
 8   <section id="intro" difficulty="easy" >
 9     <title>Introduction</title>
10     <p>Text ... </p>
11     <section>
12       <title>Audience</title>
13       <p>Text ... </p>
14     </section>
15     <section>
16       <title>Web Data and the Two Cultures</title>
17       <p>Text ... </p>
18       <figure height="400" width="400">
19         <title>Traditional client/server architecture</title>
20         <image source="csarch.gif"/>
21       </figure>
22       <p>Text ... </p>
23     </section>
24   </section>
25   <section id="syntax" difficulty="medium" >
26     <title>A Syntax For Data</title>
27     <p>Text ... </p>
28     <figure height="200" width="500">
29       <title>Graph representations of structures</title>
30       <image source="graphs.gif"/>
31     </figure>
32     <p>Text ... </p>
33     <section>
34       <title>Base Types</title>
35       <p>Text ... </p>
36     </section>
37     <section>
38       <title>Representing Relational Databases</title>
39       <p>Text ... </p>
40       <figure height="250" width="400">
41         <title>Examples of Relations</title>
42         <image source="relations.gif"/>
43       </figure>
44     </section>
45     <section>
46       <title>Representing Object Databases</title>
47       <p>Text ... </p>
48     </section>       
49   </section>
50 </book>

TREE - Q1

[Table of contents][Back to home page]

Prepare a (nested) table of contents for Book1, listing all the sections and their titles. Preserve the original attributes of each <section> element, if any.

magic/xml solution

 1 def local_toc(node)
 2     node.children(:section).map{|c|
 3         XML.section(c.attrs, c.child(:title), local_toc(c))
 4     }
 5 end
 6 
 7 XML.toc! {
 8     add! local_toc(XML.load('book.xml'))
 9 }

XQuery solution

declare function local:toc($book-or-section as element()) as element()*
{
    for $section in $book-or-section/section
    return
      <section>
         { $section/@* , $section/title , local:toc($section) }                 
      </section>
};

<toc>
   {
     for $s in doc("book.xml")/book return local:toc($s)
   }
</toc>

Expected output

 1 <toc>
 2     <section id="intro" difficulty="easy">
 3         <title>Introduction</title>
 4         <section>
 5             <title>Audience</title>
 6         </section>
 7         <section>
 8             <title>Web Data and the Two Cultures</title>
 9         </section>
10     </section>
11     <section id="syntax" difficulty="medium">
12         <title>A Syntax For Data</title>
13         <section>
14             <title>Base Types</title>
15         </section>
16         <section>
17             <title>Representing Relational Databases</title>
18         </section>
19         <section>
20             <title>Representing Object Databases</title>
21         </section>
22     </section>
23 </toc>

TREE - Q2

[Table of contents][Back to home page]

Prepare a (flat) figure list for Book1, listing all the figures and their titles. Preserve the original attributes of each <figure> element, if any.

magic/xml solution

1 XML.figlist! {
2     XML.load('book.xml').descendants(:figure) {|f|
3         figure!(f.attrs, f.children(:title))
4     }
5 }

XQuery solution

<figlist>
  {
    for $f in doc("book.xml")//figure
    return
        <figure>
            { $f/@* }
            { $f/title }
        </figure>
  }
</figlist>

Expected output

 1 <figlist>
 2     <figure  height="400" width="400">
 3         <title>Traditional client/server architecture</title>
 4     </figure>
 5     <figure  height="200" width="500">
 6         <title>Graph representations of structures</title>
 7     </figure>
 8     <figure  height="250" width ="400">
 9         <title>Examples of Relations</title>
10     </figure>
11 </figlist>

TREE - Q3

[Table of contents][Back to home page]

How many sections are in Book1, and how many figures?

magic/xml solution

1 doc = XML.load('book.xml')
2 
3 XML.section_count!(doc.descendants(:section).size)
4 XML.figure_count!(doc.descendants(:figure).size)

XQuery solution

<section_count>{ count(doc("book.xml")//section) }</section_count>, 
<figure_count>{ count(doc("book.xml")//figure) }</figure_count>

Expected output

1 <section_count>7</section_count>
2 <figure_count>3</figure_count>

TREE - Q4

[Table of contents][Back to home page]

How many top-level sections are in Book1?

magic/xml solution

1 XML.top_section_count!(XML.load('book.xml').children(:section).size)

XQuery solution

<top_section_count>
 { 
   count(doc("book.xml")/book/section) 
 }
</top_section_count>

Expected output

1 <top_section_count>2</top_section_count>

TREE - Q5

[Table of contents][Back to home page]

Make a flat list of the section elements in Book1. In place of its original attributes, each section element should have two attributes, containing the title of the section and the number of figures immediately contained in the section.

magic/xml solution

1 XML.section_list! {
2     XML.load('book.xml').descendants(:section) {|s|
3         section!({
4             :title => s[:@title],
5             :figcount => s.children(:figure).size,
6         })
7     }
8 }

XQuery solution

<section_list>
  {
    for $s in doc("book.xml")//section
    let $f := $s/figure
    return
        <section title="{ $s/title/text() }" figcount="{ count($f) }"/>
  }
</section_list>

Expected output

 1 <section_list>
 2     <section title="Introduction" figcount="0"/>
 3     <section title="Audience" figcount="0"/>
 4     <section title="Web Data and the Two Cultures" figcount="1"/>
 5     <section title="A Syntax For Data" figcount="1"/>
 6     <section title="Base Types" figcount="0"/>
 7     <section title="Representing Relational Databases" figcount="1"/>
 8     <section title="Representing Object Databases" figcount="0"/>
 9 </section_list>

TREE - Q6

[Table of contents][Back to home page]

Make a nested list of the section elements in Book1, preserving their original attributes and hierarchy. Inside each section element, include the title of the section and an element that includes the number of figures immediately contained in the section.

magic/xml solution

 1 def section_summary(s)
 2     XML.section(s.attrs) {
 3         add! s.child(:title)
 4         figcount! s.children(:figure).size
 5         add! s.children(:section).map{|c| section_summary(c)}
 6     }
 7 end
 8 
 9 XML.toc! {
10     XML.load('book.xml').children(:section) {|s|
11         add! section_summary(s)
12     }
13 }

XQuery solution

declare function local:section-summary($book-or-section as element()*)
  as element()*
{
  for $section in $book-or-section
  return
    <section>
       { $section/@* }
       { $section/title }       
       <figcount>         
         { count($section/figure) }
       </figcount>                
       { local:section-summary($section/section) }                      
    </section>
};

<toc>
  {
    for $s in doc("book.xml")/book/section
    return local:section-summary($s)
  }
</toc>

Expected output

 1 <toc>
 2     <section id="intro" difficulty="easy">
 3         <title>Introduction</title>
 4         <figcount>0</figcount>
 5         <section>
 6             <title>Audience</title>
 7             <figcount>0</figcount>
 8         </section>
 9         <section>
10             <title>Web Data and the Two Cultures</title>
11             <figcount>1</figcount>
12         </section>
13     </section>
14     <section id="syntax" difficulty="medium">
15         <title>A Syntax For Data</title>
16         <figcount>1</figcount>
17         <section>
18             <title>Base Types</title>
19             <figcount>0</figcount>
20         </section>
21         <section>
22             <title>Representing Relational Databases</title>
23             <figcount>1</figcount>
24         </section>
25         <section>
26             <title>Representing Object Databases</title>
27             <figcount>0</figcount>
28         </section>
29     </section>
30 </toc>

Input for XMP - bib.xml

[Table of contents][Back to home page]
 1 <bib>
 2     <book year="1994">
 3         <title>TCP/IP Illustrated</title>
 4         <author><last>Stevens</last><first>W.</first></author>
 5         <publisher>Addison-Wesley</publisher>
 6         <price>65.95</price>
 7     </book>
 8  
 9     <book year="1992">
10         <title>Advanced Programming in the Unix environment</title>
11         <author><last>Stevens</last><first>W.</first></author>
12         <publisher>Addison-Wesley</publisher>
13         <price>65.95</price>
14     </book>
15  
16     <book year="2000">
17         <title>Data on the Web</title>
18         <author><last>Abiteboul</last><first>Serge</first></author>
19         <author><last>Buneman</last><first>Peter</first></author>
20         <author><last>Suciu</last><first>Dan</first></author>
21         <publisher>Morgan Kaufmann Publishers</publisher>
22         <price>39.95</price>
23     </book>
24  
25     <book year="1999">
26         <title>The Economics of Technology and Content for Digital TV</title>
27         <editor>
28                <last>Gerbarg</last><first>Darcy</first>
29                 <affiliation>CITI</affiliation>
30         </editor>
31             <publisher>Kluwer Academic Publishers</publisher>
32         <price>129.95</price>
33     </book>
34  
35 </bib>

Input for XMP - books.xml

[Table of contents][Back to home page]
 1 <chapter>
 2     <title>Data Model</title>
 3     <section>
 4         <title>Syntax For Data Model</title>
 5     </section>
 6     <section>
 7         <title>XML</title>
 8         <section>
 9             <title>Basic Syntax</title>
10         </section>
11         <section>
12             <title>XML and Semistructured Data</title>
13         </section>
14     </section>
15 </chapter>

Input for XMP - prices.xml

[Table of contents][Back to home page]
 1 <prices>
 2     <book>
 3         <title>Advanced Programming in the Unix environment</title>
 4         <source>bstore2.example.com</source>
 5         <price>65.95</price>
 6     </book>
 7     <book>
 8         <title>Advanced Programming in the Unix environment</title>
 9         <source>bstore1.example.com</source>
10         <price>65.95</price>
11     </book>
12     <book>
13         <title>TCP/IP Illustrated</title>
14         <source>bstore2.example.com</source>
15         <price>65.95</price>
16     </book>
17     <book>
18         <title>TCP/IP Illustrated</title>
19         <source>bstore1.example.com</source>
20         <price>65.95</price>
21     </book>
22     <book>
23         <title>Data on the Web</title>
24         <source>bstore2.example.com</source>
25         <price>34.95</price>
26     </book>
27     <book>
28         <title>Data on the Web</title>
29         <source>bstore1.example.com</source>
30         <price>39.95</price>
31     </book>
32 </prices>

Input for XMP - reviews.xml

[Table of contents][Back to home page]
 1 <reviews>
 2     <entry>
 3         <title>Data on the Web</title>
 4         <price>34.95</price>
 5         <review>
 6                A very good discussion of semi-structured database
 7                systems and XML.
 8         </review>
 9     </entry>
10     <entry>
11         <title>Advanced Programming in the Unix environment</title>
12         <price>65.95</price>
13         <review>
14                A clear and detailed discussion of UNIX programming.
15         </review>
16     </entry>
17     <entry>
18         <title>TCP/IP Illustrated</title>
19         <price>65.95</price>
20         <review>
21                One of the best books on TCP/IP.
22         </review>
23     </entry>
24 </reviews>

XMP - Q1

[Table of contents][Back to home page]

List books published by Addison-Wesley after 1991, including their year and title.

magic/xml solution

1 XML.bib! {
2     XML.load('bib.xml').children(:book) {|b|
3         if b[:@publisher] == "Addison-Wesley" and b[:year].to_i > 1991
4             book!({:year => b[:year]}, b.child(:title))
5         end
6     }
7 }

XQuery solution

<bib>
 {
  for $b in doc("http://bstore1.example.com/bib.xml")/bib/book
  where $b/publisher = "Addison-Wesley" and $b/@year > 1991
  return
    <book year="{ $b/@year }">
     { $b/title }
    </book>
 }
</bib>

Expected output

1 <bib>
2     <book year="1994">
3         <title>TCP/IP Illustrated</title>
4     </book>
5     <book year="1992">
6         <title>Advanced Programming in the Unix environment</title>
7     </book>
8 </bib>

XMP - Q2

[Table of contents][Back to home page]

Create a flat list of all the title-author pairs, with each pair enclosed in a "result" element.

magic/xml solution

1 XML.results! {
2     XML.load('bib.xml').children(:book) {|b|
3         t = b.child(:title)
4         b.children(:author) {|a|
5             result!(t,a)
6         }
7     }
8 }

XQuery solution

<results>
  {
    for $b in doc("http://bstore1.example.com/bib.xml")/bib/book,
        $t in $b/title,
        $a in $b/author
    return
        <result>
            { $t }    
            { $a }
        </result>
  }
</results>

Expected output

 1 <results>
 2     <result>
 3         <title>TCP/IP Illustrated</title>
 4         <author>
 5             <last>Stevens</last>
 6             <first>W.</first>
 7         </author>
 8     </result>
 9     <result>
10         <title>Advanced Programming in the Unix environment</title>
11         <author>
12             <last>Stevens</last>
13             <first>W.</first>
14         </author>
15     </result>
16     <result>
17         <title>Data on the Web</title>
18         <author>
19             <last>Abiteboul</last>
20             <first>Serge</first>
21         </author>
22     </result>
23     <result>
24         <title>Data on the Web</title>
25         <author>
26             <last>Buneman</last>
27             <first>Peter</first>
28         </author>
29     </result>
30     <result>
31         <title>Data on the Web</title>
32         <author>
33             <last>Suciu</last>
34             <first>Dan</first>
35         </author>
36     </result>
37 </results>

XMP - Q3

[Table of contents][Back to home page]

For each book in the bibliography, list the title and authors, grouped inside a "result" element.

magic/xml solution

1 XML.results! {
2     XML.load('bib.xml').children(:book) {|b|
3         result!(b.children(:title), b.children(:author))
4     }
5 }

XQuery solution

<results>
{
    for $b in doc("http://bstore1.example.com/bib.xml")/bib/book
    return
        <result>
            { $b/title }
            { $b/author  }
        </result>
}
</results> 

Expected output

 1 <results>
 2     <result>
 3         <title>TCP/IP Illustrated</title>
 4         <author>
 5             <last>Stevens</last>
 6             <first>W.</first>
 7         </author>
 8     </result>
 9     <result>
10         <title>Advanced Programming in the Unix environment</title>
11         <author>
12             <last>Stevens</last>
13             <first>W.</first>
14         </author>
15     </result>
16     <result>
17         <title>Data on the Web</title>
18         <author>
19             <last>Abiteboul</last>
20             <first>Serge</first>
21         </author>
22         <author>
23             <last>Buneman</last>
24             <first>Peter</first>
25         </author>
26         <author>
27             <last>Suciu</last>
28             <first>Dan</first>
29         </author>
30     </result>
31     <result>
32         <title>The Economics of Technology and Content for Digital TV</title>
33     </result>
34 </results>

XMP - Q4

[Table of contents][Back to home page]

For each author in the bibliography, list the author's name and the titles of all books by that author, grouped inside a "result" element.

magic/xml solution

 1 XML.results! {
 2     doc = XML.load('bib.xml')
 3     a = doc.descendants(:author)
 4     books = doc.children(:book)
 5 
 6     a.map{|node| 
 7         [node[:@last], node[:@first]]
 8     }.uniq.sort.each {|last, first|
 9         result! {
10             author! {
11                 last! last
12                 first! first
13             }
14             books.each{|b|
15                 next unless b.children(:author).any?{|ba|
16                     ba[:@last] == last and ba[:@first] == first
17                 }
18                 add! b.children(:title)
19             }
20         }
21     }
22 }

XQuery solution

<results>
  {
    let $a := doc("http://bstore1.example.com/bib/bib.xml")//author
    for $last in distinct-values($a/last),
        $first in distinct-values($a[last=$last]/first)
    order by $last, $first
    return
        <result>
            <author>
               <last>{ $last }</last>
               <first>{ $first }</first>
            </author>
            {
                for $b in doc("http://bstore1.example.com/bib.xml")/bib/book
                where some $ba in $b/author 
                      satisfies ($ba/last = $last and $ba/first=$first)
                return $b/title
            }
        </result>
  }
</results>

Expected output

 1 <results>
 2     <result>
 3         <author>
 4             <last>Abiteboul</last>
 5             <first>Serge</first>
 6         </author>
 7         <title>Data on the Web</title>
 8     </result>
 9     <result>
10         <author>
11             <last>Buneman</last>
12             <first>Peter</first>
13         </author>
14         <title>Data on the Web</title>
15     </result>
16     <result>
17         <author>
18             <last>Stevens</last>
19             <first>W.</first>
20         </author>
21         <title>TCP/IP Illustrated</title>
22         <title>Advanced Programming in the Unix environment</title>
23     </result>
24     <result>
25         <author>
26             <last>Suciu</last>
27             <first>Dan</first>
28         </author>
29         <title>Data on the Web</title>
30     </result>
31 </results>

XMP - Q5

[Table of contents][Back to home page]

For each book found at both bstore1.example.com and bstore2.example.com, list the title of the book and its price from each source.

magic/xml solution

 1 xml!(:"books-with-prices") {
 2     books = XML.load("bib.xml").descendants(:book)
 3     entries = XML.load("reviews.xml").descendants(:entry)
 4     books.each{|b|
 5         entries.each{|a|
 6             next unless a[:@title] == b[:@title]
 7             xml!(:"book-with-prices") {
 8                 add! b.child(:title)
 9                 xml!(:"price-bstore2", a[:@price])
10                 xml!(:"price-bstore1", b[:@price])
11             }
12         }
13     }
14 }

XQuery solution

<books-with-prices>
  {
    for $b in doc("http://bstore1.example.com/bib.xml")//book,
        $a in doc("http://bstore2.example.com/reviews.xml")//entry
    where $b/title = $a/title
    return
        <book-with-prices>
            { $b/title }
            <price-bstore2>{ $a/price/text() }</price-bstore2>
            <price-bstore1>{ $b/price/text() }</price-bstore1>
        </book-with-prices>
  }
</books-with-prices>

Expected output

 1 <books-with-prices>
 2     <book-with-prices>
 3         <title>TCP/IP Illustrated</title>
 4         <price-bstore2>65.95</price-bstore2>
 5         <price-bstore1>65.95</price-bstore1>
 6     </book-with-prices>
 7     <book-with-prices>
 8         <title>Advanced Programming in the Unix environment</title>
 9         <price-bstore2>65.95</price-bstore2>
10         <price-bstore1>65.95</price-bstore1>
11     </book-with-prices>
12     <book-with-prices>
13         <title>Data on the Web</title>
14         <price-bstore2>34.95</price-bstore2>
15         <price-bstore1>39.95</price-bstore1>
16     </book-with-prices>
17 </books-with-prices>

XMP - Q6

[Table of contents][Back to home page]

For each book that has at least one author, list the title and first two authors, and an empty "et-al" element if the book has additional authors.

magic/xml solution

 1 XML.bib! {
 2     XML.load('bib.xml').children(:book) {|b|
 3         next unless b.children(:author).size > 0
 4         book! {
 5             add! b.children(:title)
 6             authors = b.children(:author)
 7             add! authors[0,2]
 8             xml!(:"et-al") if authors.size > 2
 9         }
10     }
11 }

XQuery solution

<bib>
  {
    for $b in doc("http://bstore1.example.com/bib.xml")//book
    where count($b/author) > 0
    return
        <book>
            { $b/title }
            {
                for $a in $b/author[position()<=2]  
                return $a
            }
            {
                if (count($b/author) > 2)
                 then <et-al/>
                 else ()
            }
        </book>
  }
</bib>

Expected output

 1 <bib>
 2     <book>
 3         <title>TCP/IP Illustrated</title>
 4         <author>
 5             <last>Stevens</last>
 6             <first>W.</first>
 7         </author>
 8     </book>
 9     <book>
10         <title>Advanced Programming in the Unix environment</title>
11         <author>
12             <last>Stevens</last>
13             <first>W.</first>
14         </author>
15     </book>
16     <book>
17         <title>Data on the Web</title>
18         <author>
19             <last>Abiteboul</last>
20             <first>Serge</first>
21         </author>
22         <author>
23             <last>Buneman</last>
24             <first>Peter</first>
25         </author>
26         <et-al/>
27     </book>
28 </bib>

XMP - Q7

[Table of contents][Back to home page]

List the titles and years of all books published by Addison-Wesley after 1991, in alphabetic order.

magic/xml solution

1 XML.bib! {
2     XML.load('bib.xml').children(:book).find_all{|b|
3         b[:@publisher] == "Addison-Wesley" and
4         b[:year].to_i > 1991
5     }.sort_by{|b| b[:@title] }.each {|b|
6         book!({:year => b[:year]}, b.child(:title))
7     }
8 }

XQuery solution

<bib>
  {
    for $b in doc("http://bstore1.example.com/bib.xml")//book
    where $b/publisher = "Addison-Wesley" and $b/@year > 1991
    order by $b/title
    return
        <book>
            { $b/@year }
            { $b/title }
        </book>
  }
</bib>

Expected output

1 <bib>
2     <book year="1992">
3         <title>Advanced Programming in the Unix environment</title>
4     </book>
5     <book year="1994">
6         <title>TCP/IP Illustrated</title>
7     </book>
8 </bib>

XMP - Q8

[Table of contents][Back to home page]

Find books in which the name of some element ends with the string "or" and the same element contains the string "Suciu" somewhere in its content. For each such book, return the title and the qualifying element.

magic/xml solution

1 XML.load('bib.xml').children(:book) {|b|
2     b.descendants {|e|
3         if e.is_a? XML and e =~ /Suciu/ and e.name.to_s =~ /or$/
4             XML.book!(b.child(:title), e)
5         end
6     }
7 }

XQuery solution

for $b in doc("http://bstore1.example.com/bib.xml")//book
let $e := $b/*[contains(string(.), "Suciu") 
               and ends-with(local-name(.), "or")]
where exists($e)
return
    <book>
        { $b/title }
        { $e }
    </book>

Expected output

1 <book>
2         <title>Data on the Web</title>
3         <author>
4             <last>Suciu</last>
5             <first>Dan</first>
6         </author>
7  </book>

XMP - Q9

[Table of contents][Back to home page]

In the document "books.xml", find all section or chapter titles that contain the word "XML", regardless of the level of nesting.

magic/xml solution

1 XML.results! {
2     XML.load('books.xml').descendants {|d|
3         if d.is_a? XML and (d.name == :chapter or d.name == :section)
4             t = d.child(:title)
5             add! t  if t =~ /XML/
6         end
7     }
8 }

XQuery solution

<results>
  {
    for $t in doc("books.xml")//(chapter | section)/title
    where contains($t/text(), "XML")
    return $t
  }
</results>

Expected output

1 <results>
2     <title>XML</title>
3     <title>XML and Semistructured Data</title>
4 </results>

XMP - Q10

[Table of contents][Back to home page]

In the document "prices.xml", find the minimum price for each book, in the form of a "minprice" element with the book title as its title attribute.

magic/xml solution

 1 XML.results! {
 2     doc = XML.load('prices.xml')
 3     doc.children(:book).children(:title).map{|node| node.text}.uniq.each{|title|
 4         minprice!({:title => title}) {
 5             price! {
 6                 text! doc.children(:book).find_all{|book|
 7                           book[:@title] == title
 8                       }.map{|book|
 9                           book[:@price].to_f 
10                       }.min
11             }
12         }
13     }
14 }

XQuery solution

<results>
  {
    let $doc := doc("prices.xml")
    for $t in distinct-values($doc//book/title)
    let $p := $doc//book[title = $t]/price
    return
      <minprice title="{ $t }">
        <price>{ min($p) }</price>
      </minprice>
  }
</results>

Expected output

 1 <results>
 2     <minprice title="Advanced Programming in the Unix environment">
 3         <price>65.95</price>
 4     </minprice>
 5     <minprice title="TCP/IP Illustrated">
 6         <price>65.95</price>
 7     </minprice>
 8     <minprice title="Data on the Web">
 9         <price>34.95</price>
10     </minprice>
11 </results>

XMP - Q11

[Table of contents][Back to home page]

For each book with an author, return the book with its title and authors. For each book with an editor, return a reference with the book title and the editor's affiliation.

magic/xml solution

 1 XML.bib! {
 2     doc = XML.load('bib.xml')
 3 
 4     doc.children(:book) {|b|
 5         if b.children(:author).size != 0
 6             book!(b.children(:title), b.children(:author))
 7         end
 8     }
 9 
10     doc.children(:book) {|b|
11         if b.children(:editor).size != 0
12             reference!(b.children(:title), b.children(:editor).children(:affiliation))
13         end
14     }
15 }

XQuery solution

<bib>
{
        for $b in doc("http://bstore1.example.com/bib.xml")//book[author]
        return
            <book>
                { $b/title }
                { $b/author }
            </book>
}
{
        for $b in doc("http://bstore1.example.com/bib.xml")//book[editor]
        return
          <reference>
            { $b/title }
            {$b/editor/affiliation}
          </reference>
}
</bib>

Expected output

 1 <bib>
 2     <book>
 3         <title>TCP/IP Illustrated</title>
 4         <author>
 5             <last>Stevens</last>
 6             <first>W.</first>
 7         </author>
 8     </book>
 9     <book>
10         <title>Advanced Programming in the Unix environment</title>
11         <author>
12             <last>Stevens</last>
13             <first>W.</first>
14         </author>
15     </book>
16     <book>
17         <title>Data on the Web</title>
18         <author>
19             <last>Abiteboul</last>
20             <first>Serge</first>
21         </author>
22         <author>
23             <last>Buneman</last>
24             <first>Peter</first>
25         </author>
26         <author>
27             <last>Suciu</last>
28             <first>Dan</first>
29         </author>
30     </book>
31     <reference>
32         <title>The Economics of Technology and Content for Digital TV</title>
33         <affiliation>CITI</affiliation>
34     </reference>
35 </bib>

XMP - Q12

[Table of contents][Back to home page]

Find pairs of books that have different titles but the same set of authors (possibly in a different order).

magic/xml solution

 1 XML.bib! {
 2     books = XML.load('bib.xml').children(:book)
 3     books.each_with_index{|book1, i|
 4         aut1 = book1.children(:author).map{|a| [a[:@last], a[:@first]]}.sort
 5 
 6         books.each_with_index{|book2, j|
 7             next unless i < j and book1[:@title] != book2[:@title]
 8             aut2 = book2.children(:author).map{|a| [a[:@last], a[:@first]]}.sort
 9 
10             xml!(:"book-pair", book1.child(:title), book2.child(:title)) if aut1 == aut2
11         }
12     }
13 }

XQuery solution

<bib>
{
    for $book1 in doc("http://bstore1.example.com/bib.xml")//book,
        $book2 in doc("http://bstore1.example.com/bib.xml")//book
    let $aut1 := for $a in $book1/author 
                 order by $a/last, $a/first
                 return $a
    let $aut2 := for $a in $book2/author 
                 order by $a/last, $a/first
                 return $a
    where $book1 << $book2
    and not($book1/title = $book2/title)
    and deep-equal($aut1, $aut2) 
    return
        <book-pair>
            { $book1/title }
            { $book2/title }
        </book-pair>
}
</bib>

Expected output

1 <bib>
2     <book-pair>
3         <title>TCP/IP Illustrated</title>
4         <title>Advanced Programming in the Unix environment</title>
5     </book-pair>
6 </bib>