Basic Principles, Lesson 2
XQuery Path Expressions

Lesson Scenario

All the lessons in this Primer are based on a real-world scenario.

XYZ.COM continues to deal with the challenge of integrating retailer EDI-formatted purchase orders with their manufacturer's requirements to use XML and file purchase orders using Web Services. In Lesson 1, we covered how XQuery operates on XML. Now, let's discover how we can use XPath to navigate the data from the incoming retailer purchase orders, which we can later use to help XYZ.COM with product inventory.

XQuery Path Expressions

XQuery path expressions are used to navigate the structure of an XML document. If you are already familiar with XPath, XQuery path expressions will look familiar. The most common task performed using path expressions is to locate nodes by identifying their location in the hierarchy of an XML document. Each path expression contains a series of one or more steps, separated by a slash '/' or double slash '//'. Each step returns a sequence of nodes.

Building path expressions is an important part of building XQuery expressions. In later lessons we will use node sequences returned by Path expressions to build full expressions.

In this lesson, we'll show how to navigate the purchase order from XYZ's retailer to return specific results from our XQuery queries. Our examples range from simple path expressions to more complicated ones. The purchase order, which we use for all examples, is shown here:


<?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" price="80.00" prod_name="atomic hammer">
	</product>
            </entry>
            <entry quantity="1" total_price="20.00">
                <product maker="ACME" price="20.00" prod_name="power springs">
	</product>
            </entry>
        </entries>
    </invoice>
    <invoice>
        <customer>Camp Mertz</customer>
        <entries n="2">
            <entry quantity="2" total_price="32.00">
                <product maker="BSA" price="16.00" prod_name="left-handed
	smoke shifter">
                </product>
            </entry>
            <entry quantity="1" total_price="13.00">
                <product maker="BSA" price="13.00" prod_name="snipe call">
	</product>
            </entry>
        </entries>
    </invoice>
</invoicecollection>

Example 1: Returning All Customers

The following expression returns all customers listed in the purchase order:

doc("po.xml")/invoicecollection/invoice/customer

This returns the following sequence:

<customer>Wile E. Coyote, Death Valley, CA</customer>
<customer>Camp Mertz</customer>

As we mentioned before, a path expression consists of a series of one or multiple steps. In this XQuery path expression, the first step is represented by the doc() function, which opens the po.xml document and returns the document node. /invoicecollection selects the invoicecollection element at the top of the document. /invoice returns invoice elements within the invoicecollection element. Similarly, /customer returns customer elements within the invoice element.

Example 2: Returning All Customers

The following XQuery path expression shows another way to return the same result as shown in Example 1.

doc("po.xml")//customer

This returns the following sequence:

<customer>Wile E. Coyote, Death Valley, CA</customer>
<customer>Camp Mertz</customer>

The double slash, //, means to select all the customer elements contained in the po.xml document, regardless of the level at which they are found in the document.

Example 3: Returning a Specific Product

In the following XQuery path expression, we again open the po.xml document using the doc() function and return the document node. We use a double slash, //, to select all product nodes in the document, regardless of where the nodes are located, but we restrict our result to only those products with a particular product name.

doc("po.xml")//product[@prod_name="snipe call"]

This returns the following sequence:

<product maker="BSA" price="13.00" prod_name="snipe call"></product>

In this XQuery path expression, we use the @ character to evaluate attributes of a specified name, in this case, prod_name. We use a double-slash, //, to locate all product nodes in the document and @ to return only nodes that have the prod_name attribute equal to "snipe call." The square brackets are used to define a predicate, or set of conditions, to define which nodes to return.

Example 4: Returning All Products Ordered by a Specific Customer

Having covered the basics of XQuery path expressions, we can now build more complex paths. To compare each retailer purchase order against XYZ.COM's internal inventory, we need to know what products are being ordered by each customer. Consider the following expression that returns attribute values for prod_name for the customer "Camp Mertz."

doc("po.xml")/invoicecollection/invoice
    [customer="Camp Mertz"]//product/@prod_name

This returns the following sequence:

prod_name="left-handed smoke shifter" prod_name="snipe call"

This path expression uses five steps to return the node sequence we are looking for. First, the doc() function opens the po.xml document and returns the document node. Second, /invoicecollection returns the top node. Third, /invoice returns each invoice child node within the invoicecollection element. Fourth, by specifying a predicate, we only return invoice nodes from the customer Camp Mertz. Finally, we locate each product node in every Camp Mertz order returning all the product names.

Example 5: Returning All Products Ordered by a Specific Customer and the Quantity of Each Order

For XYZ.COM, inventory tracking is of great importance, so the company also needs to know the amount of each product that a customer purchases, including product name and the quantity of product ordered.

In this case, we need multiple XQuery queries to obtain the data we need.

First, we obtain the nodes that describe the quantity of each product ordered.

doc("po.xml")//entry/@quantity

This returns the following sequence:

quantity="2" quantity="1" quantity="2" quantity="1"

Next, we obtain the nodes that provide the name of each product ordered.

doc("po.xml")//entry/product/@prod_name

This returns the following sequence:

prod_name="atomic hammer" prod_name="power springs" 
prod_name="left-handed smoke shifter" prod_name="snipe call"

Finally, to use our node sequences, we need to tie them together with another XQuery query, which you'll learn how to do in Lesson 3.

Summary

XQuery path expressions are used to navigate the structure of XML data and are similar to XPath expressions.

Next Lesson