{short description of image}

XQL Tutorial

Jonathan Robie, R&D Fellow, Software AG
jonathan.robie@sagus.com
Originally posted: 26 Mar 1999
Last revised: 26 Mar 1999

This tutorial discusses the simplest XQL queries, which are also likely to be the most common. In this tutorial, we will present a quick overview of XQL without taking the time to be precise.

A simple string is taken to be an element name. For instance, this query specification returns all <table> elements:

table

The child operator ("/") indicates hierarchy. This query specification returns <author> elements that are children of <front> elements:

front/author

The root of a document may be indicated by a leading "/" operator:

/novel/front/author

Note: in XQL, the root of a document refers to the document entity, in the technical XML sense, which is basically equivalent to the document itself. It is not the same as the root element, which is the element that contains the rest of the elements in the document. The document root always contains the root element, but it may also contain a doctype, processing instructions, and comments. In this example, <novel> would be the root element.

Paths are always described from the top down, and unless otherwise specified, the right-most element on the path is returned. For instance, in the above example, <author> elements would be returned.

The content of an element or the value of an attribute may be specified using the equals operator ("="). The following returns all authors with the name "Theodore Seuss Geisel":

front/author='Theodore Seuss Geisel'

Attribute names begin with "@". They are treated as children of the elements to which they belong:

front/author/address/@type='email'

The descendant operator ("//") indicates any number of intervening levels. The following shows addresses anywhere within front:

front//address

When the descendant operator is found at the start of a path, it means all nodes descended from the document. This query will find any address in the document:

//address

The filter operator ("[ ]") filters the set of nodes to its left based on the conditions inside the brackets. The following returns addresses. Each of these addresses must have an attribute called "type" with the value "email":

front/author/address[@type='email']

Note that "address[@type='email']" returns addresses, but "address/@type='email'" returns type attributes.

Multiple conditions may be combined using Boolean operators.

front/author='Theodore Seuss Geisel'[@gender='male' and @shoesize='9EEEE']

Brackets are also used for subscripts, which indicate position within a document. The following refers to sections 0, 3, 4, 5, and 8, plus the last section:

section[0, 3 to 5, 8, -1]

Conditions and subscripts may not both occur in the same brackets, but both uses of brackets may occur in the same query. The following refers to the first three sections whose level attributes have the value "3"; in other words, it returns the first three "level 3" sections:

section[@level='3'][0 to 2]

Now that we know the basics, let's take a look at a document and try some XQL queries on it. The following is an invoice document. Traditionally, invoices are often stored in databases, but invoices are both documents and data. XQL is designed to work on both documents and data, provided they are represented via XML through some interface. This document will be the basis for the sample queries that follow:

<?xml version="1.0"?>
<invoicecollection>
<invoice>
  <customer>
       Wile E. Coyote, Death Valley, CA
  </customer>
  <annotation>
        Customer asked that we guarantee return rights if these items
         should fail in desert conditions. This was approved by Marty
         Melliore, general manager.
  </annotation>
  <entries n=2>
     <entry quantity=2  total_price="134.00">
        <product maker="ACME" prod_name="screwdriver" price="80.00"/>
     </entry>
     <entry quantity=1  total_price="20.00">
        <product maker="ACME" prod_name="power wrench" price="20.00"/>
     </entry>
  </entries>
</invoice>
<invoice>
  <customer>
       Camp Mertz
  </customer>
  <entries n=2>
     <entry quantity=2  total_price="32.00">
        <product maker="BSA" prod_name="left-handed smoke shifter" price="16.00"/>
     </entry>
     <entry quantity=1  total_price="13.00">
        <product maker="BSA" prod_name="snipe call" price="13.00"/>
     </entry>
  </entries>
</invoice>
</invoicecollection>

Now let's look at some sample queries. Suppose we wanted to see just the customers from the database. We could do the following query:

Query:
   //customer
Result:
	  <xql:result>
	    <customer>
      Wile E. Coyote, Death Valley, CA
     </customer>
     <customer>
      Camp Mertz
     </customer>
	  </xql:result>

We might want to look at all the products manufactured by BSA. This query would do the trick:

Query:
   //product[@maker='BSA']
Result:
   <xql:result>
      <product maker="BSA" prod_name="left-handed smoke shifter" price="16.00"/>
      <product maker="BSA" prod_name="snipe call" price="13.00"/>
   </xql:result>

Filters are very useful when specifying conditions on paths that are not the same as what is returned. For instance, the following query returns the products ordered by Camp Mertz:

Query:
   //invoice[customer='Wile E. Coyote, Death Valley, CA']//product
Result:
   <xql:result>
      <product maker="ACME" prod_name="screwdriver" price="80.00"/>
      <product maker="ACME" prod_name="power wrench" price="20.00"/>
   </xql:result>