Introducing XQuery

XLink and XPointer are typical of the XPath 1.0 approach to accessing datayou can embed XPath 1.0 expressions directly in your XLink and XPointer expressions. However, data handling is becoming appreciably more sophisticated in XPath 2.0 and XQuery 1.0. To show how much more sophisticated, we'll take a look at XQuery 1.0. XQuery can't be directly compared to XLink and XPointer because it's an entire language (an extension to XPath 2.0), not just a way of using XPath expressionsand that's the whole point. These days, the relative simplicity of XLink and XPointer is not enough; now we need more power, and that's what a language like XQuery gives us. As you're going to see, XQuery goes far beyond XLink and XPointer, and putting it to work will give us an introduction to XPath 2.0, which starts in the next chapter.

XQuery 1.0 is designed to work with XPath 2.0, and it's designed to treat XML documents much as you'd treat databases. In fact, XQuery does function something like Structured Query Language (SQL) does with relational databases. Here's what W3C says about XQuery:

"XML is a versatile markup language, capable of labeling the information content of diverse data sources including structured and semi-structured documents, relational databases, and object repositories. A query language that uses the structure of XML intelligently can express queries across all these kinds of data, whether physically stored in XML or viewed as XML via middleware. This specification describes a query language called XQuery, which is designed to be broadly applicable across many types of XML data sources."

XQuery 1.0 and XSLT 2.0 both work with XPath 2.0. In particular, XQuery 1.0 is an extension of XPath 2.0, and XPath 2.0 is an embedded language in XSLT 2.0. Although you could replace XPath 2.0 in XSLT 2.0 with another language and it would work as well, XPath 2.0 is completely integral to XQuery 1.0. Another big difference is that XQuery 1.0 and XPath 2.0 are much more strongly typed than XPointer/XLink and XPath 1.0, so we'll have to be more careful about the data types we're working with (strings, integers, and so on) than we were before. XQuery gives you not only a data model to let you interpret XML documents, but also a set of operators and functions to let you extract data from those documents.

The W3C XQuery specification is still subject to change at this time. This specification is divided into several working draftsthe main XQuery 1.0 working draft is at http://www.w3.org/TR/xquery/, but there are also working drafts for XQuery semantics, the data model, and serialization. Here's an overview of what's available online as of this writing:

  • The XQuery activity page gives an overview http://www.w3.org/XML/Query

  • The XQuery version 1.0 Working Draft http://www.w3.org/TR/xquery/

  • The XQuery 1.0 and XPath 2.0 Data Model http://www.w3.org/TR/xpath-datamodel/

  • The XQuery 1.0 and XPath 2.0 Formal Semantics http://www.w3.org/TR/xquery-semantics/

  • The XQuery 1.0 and XPath 2.0 Functions and Operators http://www.w3.org/TR/xquery-operators/

  • The XML Query Requirements, an overview of what's going to go into XQuery, in Working Draft form http://www.w3.org/TR/xquery-requirements/

XQuery is already very popular, and there are a number of implementations of XQuery 1.0 out there. Here's a starter list (check out the XQuery Working Group 's Web page at http://www.w3.org/XML/Query for more implementations and to get new URLs if any of these no longer work) :

  • The XQuery 1.0 Grammar Test Page http://www.w3.org/2003/05/applets/xqueryApplet.html

  • The XPath 2.0 Grammar Test Page http://www.w3.org/2003/05/applets/xpathApplet.html

  • BEA's Liquid Data http://edocs.bea.com/liquiddata/docs10/prodover/concepts.html

  • Bluestream Database Software Corp.'s XStreamDBhttp://www.bluestream.com/dr/?page=Home/Products/XStreamDB/

  • Cerisent's XQE http://cerisent.com/cerisent-xqe.html

  • Cognetic Systems' XQuantumhttp://www.cogneticsystems.com/xquery/xquery.html

  • Enosys Software's XQuery Demohttp://xquerydemo.enosyssoftware.com

  • eXcelon's eXtensible Information Server (XIS 3.1 SP2)http://www.exln.com/products/xis/

  • Stylus Studio 4.5, with XQuery and XML Schema support http://www.exln.com/products/stylusstudio

  • E-XMLMedia's XMLizer http://www.e-xmlmedia.com/prod/xmlizer.htm

  • Fatdog's XQEngine http://www.fatdog.com/

  • GAEL's Derby http://www.gael.fr/derby/

  • GNU's Qexo (Kawa-Query) http://www.qexo.org/Compiles XQuery on-the-fly to Java bytecodes

  • Ipedo's XML Database v3.0 http://www.ipedo.com

  • IPSI's IPSI-XQ http://ipsi.fhg.de/oasys/projects/ipsi-xq/index_e.html

  • Lucent's Galax http://db.bell-labs.com/galax/. Open -source

  • Microsoft's XML Query Language Demo http://xqueryservices.com

  • Neocore's XML management system (XMS) http://www.neocore.com/products/products.htm

  • Nimble Technology's Nimble Integration Suite http://www.nimble.com/

  • OpenLink Software's Virtuoso Universal Server http://demo.openlinksw.com:8890/xqdemo

  • Oracle's XML DB http://otn.oracle.com/tech/xml/xmldb/htdocs/querying_xml.html

  • Politecnico di Milano's XQBE http://dbgroup.elet.polimi.it/xquery/xqbedownload.html

  • QuiLogic's SQL/XML-IMDB http://www.quilogic.cc/xml.htm

  • Software AG's Tamino XML Server http://www.softwareag.com/tamino/News/tamino_41.htm

  • Tamino XML Query Demo http://tamino.demozone.softwareag.com/demoXQuery/index.html

  • SourceForge 's Saxon http://saxon.sourceforge.net/

  • SourceForge's XQuench http://xquench.sourceforge.net/. Open-source

  • XQuery Lite http://sourceforge.net/projects/phpxmlclasses/

  • X-Hive's XQuery demo http://www.x-hive.com/xquery

  • XML Global's GoXML DB http://www.xmlglobal.com/prod/xmlworkbench/

To see XQuery at work, we're going to use it with Lucent's Galax XQuery processor, one of the foremost XQuery implementations. You can download Galax for free at http://db.bell-labs.com/galax/. And you can see an online demo at http://db.bell-labs.com/galax/demo/galax_demo.html.

To use XQuery, we'll need an XML document, and we'll use the one you see in Listing 6.3 ( ch06_03.xml ). This XML document holds information about a number of meetings set up for two teams of employees . We'll use XQuery to extract information about the meetings and meeting locations from this document.

Listing 6.3 A Sample XML Document ( ch06_03.xml )
 <?xml version="1.0" encoding="UTF-8"?> <employees>     <title>List of employees</title>     <employee>John Thompson</employee>     <employee>Edward Hastings</employee>     <employee>Traci Franklin</employee>     <employee>Frank Thomas</employee>     <meeting ID="Introduction" time="evening" >         <title>Introduction</title>         <p>Welcome</p>         <meeting>             <title>Team 1</title>             <p>Team 1 meeting</p>         </meeting>         <meeting>             <title>Team 2</title>             <p>Team 2 meeting</p>             <location address="Auditorium">                 <title>Building 1</title>                 <phone number="555-2221"/>             </location>             <p>Getting Started</p>         </meeting>     </meeting>     <meeting ID="Leadership" time="morning" >         <title>Leadership</title>         <p>Breakfast meeting</p>         <location address="Meeting Room 5">             <title>Building 2</title>                 <phone number="555-2222"/>         </location>         <p>Understanding the Issues</p>         <meeting>             <title>Team 1</title>             <p>Team 1 meeting</p>         </meeting>         <meeting>             <title>Team 2</title>             <p>Team 2 meeting</p>             <location address="Auditorium">                 <title>Building 3</title>                 <phone number="555-2223"/>             </location>         </meeting>         <meeting>             <title>Closing Statements</title>             <p>Wrapping things up</p>         </meeting>     </meeting> </employees> 

We're going to use XQuery to extract data from ch06_03.xml using Galax, and we'll use two XQuery files to do it. The first file will hold XQuery context code, where we'll declare the XML elements in ch06_03.xml and the XQuery functions we'll use. The other XQuery file will hold the template we'll use to query our XML document. (Splitting our XQuery code into two parts is not necessary for working with XQuery in general; we're just doing it to work with Galax.)

The XQuery context file, ch06_04.xq , will start by defining all the XML elements in our sample XML document so that Galax can check the validity of that document. Defining the XML elements we'll be using can be done with this XML DTD-like syntax, which is specific to Galax:

 
 define element employees {     element title,     element employee+,     element meeting+ } define element title {xsd:string} define element employee {xsd:string} define element meeting {     attribute ID {xsd:string}?,     attribute time {xsd:string}?,     element title,       (element p  element location  element meeting)* } define element p {xsd:string} define element location {     attribute address { xsd:string },     element title,     element phone } define element phone {     attribute number {xsd:string} } 

Now we need to indicate to Galax what XML document our data can be found in, and that's ch06_03.xml here. In this case, we'll associate that document with an XQuery variable , $employeesList , making the data in that document available to our XQuery code. XQuery variable names begin with a $ sign, and the following example shows how we define our global variable named $employeesList to hold the data from ch06_03.xml . (The glx:document-validate function is specific to Galax that reads in a document and validates it because how a document is validated is implementation-specific; in XPath 2.0, you can read in a document without validating it with the fn:doc function, as we'll see in Chapter 12, "XPath 2.0 Node and Sequence Functions.")

 
 define global $employeesList {treat as document employees (glx:document-validate("ch06_03.xml", "employees"))} 

XQuery also lets you define your own functions . To see how this works, we'll create a function named summation here, which will return a summation of various different types of elements. Here's how we define summation , indicating that we want to pass an XML element to it:

 
 define function summation($elem as element) as element* {     .     .     . } 

We begin our XQuery function by getting the name of the element we're working with using the XQuery local-name function, like this:

 
 define function summation($elem as element) as element* {  let $name := local-name($elem)  .         .         . } 

We can check if we've been passed a <meeting> element, and if so, return a summation of that element this way:

 
 define function summation($elem as element) as element* {     let $name := local-name($elem)     return  if ($name = "meeting")   then   <meeting>   {$elem/@*}   {for $item in $elem/* return summation($item)}   </meeting>  .         .         . } 

As far as other elements go, we'll return only <title> elements, like this (this function, by the way, points out one of the differences between XSLT and XQueryin XSLT, you'd need four templates to do this; in XQuery, you only need one function):

 
 define function summation($elem as element) as element* {     let $name := local-name($elem)     return         if ($name = "meeting")         then             <meeting>                 {$elem/@*}                 {for $item in $elem/* return summation($item)}              </meeting>  else if ($name = "title")   then $elem   else ()  } 

That's it; now our summation function will return summations for <meeting> and <title> elements. That completes our XQuery context file, ch06_04.xq , which you can see in Listing 6.4.

Listing 6.4 Our Context XQuery Document ( ch06_04.xq )
 define element employees {     element title,     element employee+,     element meeting+ } define element title {xsd:string} define element employee {xsd:string} define element meeting {     attribute ID {xsd:string}?,     attribute time {xsd:string}?,     element title,       (element p  element location  element meeting)* } define element p {xsd:string} define element location {     attribute address { xsd:string },     element title,     element phone } define element phone {     attribute number {xsd:string} } define element meetingSummary {     attribute ID {xsd:string}?,     attribute time {xsd:string}?,     element title,     element locationCount {xsd:int},     element meetingSummary* } define global $employeesList {treat as document employees     (glx:document-validate("ch06_03.xml", "employees"))} define function summation($elem as element) as element* {     let $name := local-name($elem)     return         if ($name = "meeting")         then             <meeting>                 {$elem/@*}                 {for $item in $elem/* return summation($item)}              </meeting>          else if ($name = "title")          then $elem          else () } 

The next step is to create the template file, ch06_05.xq , which will use ch06_03.xml and ch06_04.xq to extract the data we want. In this case, we'll start by creating a <meetings> element that holds a summary of the <meeting> elements in our XML document. We'll use the summation function to create this summary. Note in particular the XPath syntax here to specify the <meeting> child elements of the <employees> document element $employeesList/employees/meeting :

 
 <meetings>     {         for $meeting in $employeesList/employees/meeting return summary($meeting)     } </meetings> ; 

In this case, we're stripping out and displaying a summary of each <meeting> elementincluding all child <meeting> elements, while also preserving the <title> elements. Here's what the output of our XQuery query looks like so far:

 
 <meetings>   <meeting time="evening"     ID="Introduction">     <title>Introduction</title>     <meeting><title>Team 1</title></meeting>     <meeting><title>Team 2</title></meeting>   </meeting>   <meeting time="morning"     ID="Leadership">     <title>Leadership</title>     <meeting><title>Team 1</title></meeting>     <meeting><title>Team 2</title></meeting>     <meeting><title>Closing Statements</title></meeting>   </meeting> </meetings> 

We can also display the locations of the various meetings by selecting <location> elements in the XML document, preserving their attributes and titles, and displaying the results in a <locations> element like this:

 
 <locations>     {         for $location in $employeesList//location         return             <location>                 {$location/@*}                 {$location/title}             </location>     } </locations> ; 

This code gives us these results in the output, where we're displaying the <location> elements and their attributes, as well as any contained <title> elements:

 
 <locations>   <location address="Auditorium"><title>Building 1</title></location>   <location address="Meeting Room 5"><title>Building 2</title></location>   <location address="Auditorium"><title>Building 3</title></location> </locations> 

We might also use the XQuery count function to count the number of <meeting> elements. To count all <meeting> elements, no matter where they are in the input XML document, we can use the expression $employeesList//meeting , using the XPath // syntax to indicate any descendant:

 
 <numberMeetings>{count($employeesList//meeting)}</numberMeetings> ; 

This gives us this result:

 
 <numberMeetings>7</numberMeetings> 

And we might count the total number of <location> elements this way:

 
 <numberLocations>{count($employeesList//location)}</numberLocations> ; 

Here is the result:

 
 <numberLocations>3</numberLocations> 

Finally, we'll count the number of <meeting> elements that themselves contain <meeting> elements like this:

 
 <numberMainMeetings>     {         count($employeesList/employees/meeting)     } </numberMainMeetings> ; 

This is what appears in the output:

 
 <numberMainMeetings>2</numberMainMeetings> 

And that's ityou can see the complete XQuery query file, ch06_05.xq , in Listing 6.5.

Listing 6.5 Our XQuery Document ( ch06_05.xq )
 <meetings>     {         for $meeting in $employeesList/employees/meeting return summation($meeting)     } </meetings> ; <locations>     {         for $location in $employeesList//location         return             <location>                 {$location/@*}                 {$location/title}             </location>     } </locations> ; <numberMeetings>{count($employeesList//meeting)}</numberMeetings> ; <numberLocations>{count($employeesList//location)}</numberLocations> ; <numberMainMeetings>     {         count($employeesList/employees/meeting)     } </numberMainMeetings> ; 

Now we're ready to use Galax with our context and template XQuery files. Here's how you do that:

 
 %galax -context ch06_04.xq ch06_05.xq 

Here's what you see when you execute Galaxnote that our XQuery results are displayed as XML:

 
 %galax -context ch06_04.xq ch06_05.xq <meetings>   <meeting time="evening"     ID="Introduction">     <title>Introduction</title>     <meeting><title>Team 1</title></meeting>     <meeting><title>Team 2</title></meeting>   </meeting>   <meeting time="morning"     ID="Leadership">     <title>Leadership</title>     <meeting><title>Team 1</title></meeting>     <meeting><title>Team 2</title></meeting>     <meeting><title>Closing Statements</title></meeting>   </meeting> </meetings> <locations>   <location address="Auditorium"><title>Building 1</title></location>   <location address="Meeting Room 5"><title>Building 2</title></location>   <location address="Auditorium"><title>Building 3</title></location> </locations> <numberMeetings>7</numberMeetings> <numberLocations>3</numberLocations> <numberMainMeetings>2</numberMainMeetings> 

You can also write these results to an XML document like this, which creates the document summation.xml :

 
 %galax -context ch06_04.xq ch06_05.xq -output-xml summation.xml 

And that completes our XQuery example.

Variables? Do-it-yourself functions? You can already see in this example how much more detailed and powerful XQuery is than XLink and XPointer. In fact, XQuery is far more sophisticated and can't even be compared directly to XLink and XPointer. Instead, XQuery is better compared to XSLT, although it's even more sophisticated than XSLT isin XSLT, you're restricted to templates, but in XQuery you can create your own functions and use a flexible programming language that is far more powerful than simple XSLT templates.

As you can see, the trend is towards more and more power and sophistication. And XPath 2.0 is a big part of that. It shouldn't surprise you to learn that XPath 2.0 is much larger than XPath 1.0, and supports many more advanced techniques. XPath 2.0 also supports very strong data typing, and after you've validated an XML document, lets you make use of that data typing information. We're going to see how all this works as we plunge into XPath 2.0, coming up in Chapter 7.

We're done with XPath 1.0 now, and it's time to turn to XPath 2.0. XPath 2.0 is at the heart of the development that's going on in its cospecifications, XSLT 2.0 and XQuery 1.0, and there is a lot of material coming up, as we're going to see.



XPath. Navigating XML with XPath 1.0 and 2.0 Kick Start
XPath Kick Start: Navigating XML with XPath 1.0 and 2.0
ISBN: 0672324113
EAN: 2147483647
Year: 2002
Pages: 131

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net