Return multiple values from multiple inputs in XQuery 3.0?

Wolfpack'08 picture Wolfpack'08 · Sep 17, 2012 · Viewed 28.5k times · Source

I've tried a few things:

for $name in ('Hanz', 'Heinz', 'Hans', 'Huns', 'Hund')
where $name contains text 'Hans' using fuzzy
return $name | $name
(: returns error: Stopped at line 3, column 20: [XPTY0004] 
Union expression: node() expected, xs:string found. :)


for $name in ('Hanz', 'Heinz', 'Hans', 'Huns', 'Hund')
where $name contains text 'Hans' using fuzzy
return $name and $name
(: returns true :)

for $name in ('Hanz', 'Heinz', 'Hans', 'Huns', 'Hund')
where $name contains text 'Hans' using fuzzy
return $name, $name
(: returns error: Stopped at line 3, column 19: [XPST0008] 
Undefined variable $name. :)

What I'm trying to do is just return the name variable twice. Of course, I'd like to do something more complicated. For example, given a doc (taken from w3):

<?xml version="1.0" encoding="ISO-8859-1"?>

<bookstore>

<book category="COOKING">
  <title lang="en">Everyday Italian</title>
  <author>Giada De Laurentiis</author>
  <year>2005</year>
  <price>30.00</price>
</book>

<book category="CHILDREN">
  <title lang="en">Harry Potter</title>
  <author>J K. Rowling</author>
  <year>2005</year>
  <price>29.99</price>
</book>

<book category="WEB">
  <title lang="en">XQuery Kick Start</title>
  <author>James McGovern</author>
  <author>Per Bothner</author>
  <author>Kurt Cagle</author>
  <author>James Linn</author>
  <author>Vaidyanathan Nagarajan</author>
  <year>2003</year>
  <price>49.99</price>
</book>

<book category="WEB">
  <title lang="en">Learning XML</title>
  <author>Erik T. Ray</author>
  <year>2003</year>
  <price>39.95</price>
</book>

</bookstore>

I've tried to execute some queries I've seen in accepted answers across Stack Overflow, and I've yielded negative results. For example:

let $sep := ','
for $x in doc('test')/bookstore
  where fn:matches($x/book, 'XC')
  return fn:string-join( ($x/book/title/text(), $x/book/author/text(), 
  $x/book/price/text()), $sep)
(: Stopped at line 3, column 31: [XPTY0004] Single item expected, 
(element book { ... }, element book { ... }, ...) found. :)

--

I'd like to return the author, year, and title of any book with the category attribute equal to "web", a title element whose language attribute is English and whose value is exactly "Learining XML" and whose any child contain the text "Erik T"; or whose year is later than 2003, whose any descendant contain the text XML, and whose price is less than 20.00USD.

I think this shows the versatility of XQuery. Without being able to return, and in fact input, a list of targets, the software is essentially useless. I've found there is not a solid answer or tutorial that covers even a small portion of the above query; however, there are queries on how to do mathematical comparisons and order-by functions. These are useful in their own way, but getting started, they aren't nearly as important as being able to return multiple columns of a table based on the results found therein.

Answer

Jens Erat picture Jens Erat · Sep 17, 2012

You've been really close in your third attempt, just the parentheses have been missing:

for $name in ('Hanz', 'Heinz', 'Hans', 'Huns', 'Hund')
where $name contains text 'Hans' using fuzzy
return ($name, $name)

You can return arbitrary variables in this sequence.

Caveat: XQuery does not know nested sequences, if you try so, they will just get concatenated. If you need nested sequences, you will have to construct an XML tree which you will return, eg.

return <names>
         <name>{$name}</name>
         <name>{$name}</name>
       </names>

This one does not contain any sequences, but it should show the pattern.