Home > Articles

This chapter is from the book

This chapter is from the book

Understanding XPath

So far, this lesson has been all theory. You need this theory as a foundation for practical application, which is what the rest of this lesson is all about.

XSLT wouldn't work if it didn't have some kind of mechanism to match and select nodes and act on them. You need to be able to express which node or nodes should match. This is what XPath expressions are for. XPath is the language you use to specify which node or nodes you want to work with. Expressions in XPath can be very simple, pointing to a specific location within a document tree using absolute addressing. You can, however, make selections based on very complex rules. As you work your way through this book, you will learn to create more and more complex expressions. But, of course, you need to start simple.

Selecting Elements

If you're familiar with addresses on the World Wide Web, the most basic XPath expressions are easy to understand. A Web site is a hierarchy of files, just like an XML document is a hierarchy of elements. If you visit a Web site, you specify its root with the name of the Web site. For example, http://www.somesite.com points to the root or home page of the Web site. This is the same as http://www.somesite.com/, which is actually more accurate. What comes after this part of the address specifies where in the hierarchy of the site you want to be. So, http://www.somesite.com/menu/entrees points to the index file in the entrees directory, which is a child of the menu directory, which is a child of the root directory. The /menu/entrees path is especially interesting. It uniquely identifies a location within the Web site hierarchy, as shown in Figure 3.4.

Figure 3.4 Web site hierarchy.

Figure 3.4 shows part of the hierarchy for the Web site. Notice that /menu/entrees uniquely identifies the entrees node in the tree. If you want to select the desserts node, you change to /menu/desserts. Now look at Listing 3.1.

Listing 3.1 Menu in XML Corresponding to Figure 3.4

1: <?xml version="1.0" encoding="UTF-8"?>
2: <menu>
3:  <appetizers title="Work up an Appetite">
4:   <dish id="1" price="8.95">Crab Cakes</dish>
5:   <dish id="2" price="9.95">Jumbo Prawns</dish>
6:   <dish id="3" price="10.95">Smoked Salmon and Avocado Quesadilla</dish>
7:   <dish id="4" price="6.95">Caesar Salad</dish>
8:  </appetizers>
9:  <entrees title="Chow Time!">
10:   <dish id="5" price="19.95">Grilled Salmon</dish>
11:   <dish id="6" price="17.95">Seafood Pasta</dish>
12:   <dish id="7" price="16.95">Linguini al Pesto</dish>
13:   <dish id="8" price="18.95">Rack of Lamb</dish>
14:   <dish id="9" price="16.95">Ribs and Wings</dish>
15:  </entrees>
16:  <desserts title="To Top It Off">
17:  <dish id="10" price="6.95">Dame Blanche</dish>
18:  <dish id="11" price="5.95">Chocolat Mousse</dish>
19:  <dish id="12" price="6.95">Banana Split</dish>
20: </desserts>
21: </menu>

NOTE

You can download the sample listings in this lesson from the publisher's Web site.

The XML in Listing 3.1 has the same tree structure as that of the Web site depicted in Figure 3.4. So, just like in the Web site, /menu/entrees points to the entrees element in the XML document. Pointing to a certain node in an XML document with XPath is, as you can see, very simple. It is based on principles that you have probably used before, so they'll be familiar to you, even though you've never worked with XPath before. To see how this approach really works, look at Listing 3.2.

Listing 3.2 Stylesheet Selecting the entrees Node from Listing 3.1

1: <?xml version="1.0" encoding="UTF-8"?>
2: <xsl:stylesheet version="1.0"
3:  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:  <xsl:template match="/">
6:   <xsl:value-of select="/menu/entrees" />
7:  </xsl:template>
8:
9: </xsl:stylesheet>

The template on line 5 matches the root element of the source document. The value retrieved on line 6 is selected using the expression /menu/entrees, which matched the entrees element that is the child element of the root element menu. The result from applying Listing 3.2 to Listing 3.1 is shown in Listing 3.3.

Listing 3.3 Result from Applying Listing 3.2 to Listing 3.1

<?xml version="1.0" encoding="utf-8"?>
  Grilled Salmon
  Seafood Pasta
  Linguini al Pesto
  Rack of Lamb
  Ribs and Wings

NOTE

Be aware that the preceding sample was run with the Saxon processor. If you use another processor, the result might be slightly different. MSXSL generates UTF-16 output by default, so the result when using MSXSL will have spaces between each letter.

Listing 3.3 shows the value of all the child nodes of the entrees node. If you remember yesterday's lesson, that is exactly right, as line 6 of Listing 3.2 asks for the value of the entrees node. That node's value contains all its descendant nodes. Getting its value yields the text value of the descendant elements. This scenario is a bit confusing because it looks like Listing 3.2 actually selects a node-set consisting of all the child elements of the entrees node. If the entrees node also contains a text value, you would see that this isn't true. You can, however, create an additional template to handle the dish elements, as shown in Listing 3.4.

Listing 3.4 Stylesheet with More Control over dish Elements

1: <?xml version="1.0" encoding="UTF-8"?>
2: <xsl:stylesheet version="1.0"
3:  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:  <xsl:template match="/">
6:   <xsl:apply-templates />
7:  </xsl:template>
8:
9:  <xsl:template match="/menu/appetizers" />
10:
11:  <xsl:template match="/menu/entrees">
12:   Entrees:
13:   <xsl:apply-templates />
14:  </xsl:template>
15:
16:  <xsl:template match="/menu/desserts" />
17:
18:  <xsl:template match="dish">
19:    <xsl:value-of select="text()" />
20:  </xsl:template>
21:
22: </xsl:stylesheet>

In Listing 3.4, note that lines 9 and 16 effectively ignore the appetizers and desserts nodes in Listing 3.1 to keep the result small and to the point. The result of applying Listing 3.4 to Listing 3.1 is shown in Listing 3.5.

Listing 3.5 Result from Applying Listing 3.4 to Listing 3.1

<?xml version="1.0" encoding="utf-8"?>


   Entrees:

  
  Grilled Salmon

  Seafood Pasta

  Linguini al Pesto

  Rack of Lamb

  Ribs and Wings

In Listing 3.5, each dish node is now handled separately. The hyphen (-) in front of each dish shows that this is really the case. The whitespace appears, as I said before, because of the processor's default whitespace rules.

Getting the Value of a Single Element

The problem with the code shown so far is that it acts on an element or a set of elements. Within the set of elements (such as the dish elements), no one node is singled out. If you also address a dish node instead of matching it with a template, a reasonable assumption would be that you will get the value of a single dish node. Listing 3.6 tests this assumption.

Listing 3.6 Stylesheet Getting the Value of a dish Element

1: <?xml version="1.0" encoding="UTF-8"?>
2: <xsl:stylesheet version="1.0"
3:  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:  <xsl:template match="/">
6:   <xsl:apply-templates />
7:  </xsl:template>
8:
9:  <xsl:template match="/menu/appetizers" />
10:
11:  <xsl:template match="/menu/entrees">
12:   <xsl:value-of select="dish" />
13:  </xsl:template>
14:
15:  <xsl:template match="/menu/desserts" />
16:
17: </xsl:stylesheet>

In Listing 3.6, the template on line 11 matching the entrees element selects only the value of a dish node on line 12. Note that, compared to Listing 3.4, there is no template matching the dish element. The result for Listing 3.6 is shown in Listing 3.7.

Listing 3.7 Result from Applying Listing 3.6 to Listing 3.1

<?xml version="1.0" encoding="utf-8"?>

 Grilled Salmon

In Listing 3.7, the assumption made for Listing 3.6 is correct. Getting the value of a dish node yields the value of exactly one dish node. But what happened to the other nodes? After all, the xsl:value-of element matches dish nodes, so it, in fact, matches a node-set. The fact that you get a single value is again a result of the default behavior of XSLT. If a node-set matches a xsl:value-of selection, only the value of the first element in the node-set is used. The first element is the one that comes first in the source XML, according to the selection—in this case, the Grilled Salmon.

Now a new question arises: How do you specifically select another element in the node-set? Fortunately, you can just specify the number of the element you want to select. This, however, deviates from the path notation you are familiar with from Web sites. You need to place the number of the element you want to select between square brackets, [ and ]. Hence, you select the third dish element like this:

<xsl:value-of select="dish[3]" />

NOTE

In many programming languages, a list of elements is numbered from 0, so element number 3 is actually the fourth element in the list. XSLT numbers a list starting with 1, so element number 3 is the third element.

The value between the square brackets is called a predicate, which is a literal or expression that determines whether a certain node should be included in the selection.

Note that the preceding example uses relative addressing, which means that the selection is done based on the current location. If that is the entrees element, the third dish element in the entrees element is selected. If the current node has no child elements named dish, the value is empty.

Because predicates can be expressions, they can become quite complex, testing whether an element conforms to certain criteria. As I said at the beginning of this section, I'll discuss more complex expressions later in this book. The object now is to make you familiar with the building blocks, so let's proceed with an example based on what you've seen so far. The example in Listing 3.8 creates a menu of the day from the sample XML in Listing 3.1.

Listing 3.8 Stylesheet Creating "Today's Menu"

1: <?xml version="1.0" encoding="UTF-8"?>
2: <xsl:stylesheet version="1.0"
3:  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:  <xsl:template match="/">
6:   Today's Menu
7:    <xsl:value-of select="/menu/appetizers/dish[2]" />
8:    <xsl:value-of select="/menu/entrees/dish[3]" />
9:    <xsl:value-of select="/menu/desserts/dish[1]" />
10:  </xsl:template>
11:
12: </xsl:stylesheet>

Listing 3.8 has only one template on line 5, matching the root element. This template displays the values for different elements in Listing 3.1 using absolute addressing and number predicates. Line 7 selects the second dish element in the appetizers element; line 8, the third dish element in the entrees element; and line 9, the first dish element in the desserts element. Listing 3.9 shows the result.

Listing 3.9 Result from Applying Listing 3.8 to Listing 3.1

<?xml version="1.0" encoding="utf-8"?>
   Today's Menu
    Jumbo Prawns
    Linguini al Pesto
    Dame Blanche

Listing 3.8 contains only a template matching the root of the XML source. The rest of the stylesheet's functionality utilizes absolute addressing to get the wanted values. As you can see, this yields a list of dishes that form today's menu.

Earlier, you learned about the current node. After a template is fired, a certain node is considered the current node. A path expression doesn't contain a current node, but it does consist of context nodes. A context node is a part of an expression that operates on a certain node.

The predicates used in Listing 3.8 operate on the context node—in this case, the dish node. At one point or another, each part of the path's expression is the context node. It, however, is relevant only when you're working with predicates in a path expression. You can have predicates at several stages within the path expression, in which case the context node is the node that the predicate operates on.

You must realize that if no match occurs, nothing happens. This is also the case if a predicate holds a number for which no element exists. In that case, the number is just ignored. You don't see an error message or anything telling you that an element is missing. The clue is not that an element is missing, but rather that no element matches that particular rule, so the rule is never applied.

Selecting Attributes

So far, you've learned only about elements. But what about attributes? Earlier, I said that elements and attributes don't differ very much, so you might expect that you can address them in the same way, as Listing 3.10 tries to do.

Listing 3.10 Stylesheet Trying to Select Attributes

1: <?xml version="1.0" encoding="UTF-8"?>
2: <xsl:stylesheet version="1.0"
3:  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:  <xsl:template match="/">
6:   Dessert of the Day:
7:   <xsl:value-of select="/menu/desserts/dish[2]" />
8:   Price: <xsl:value-of select="/menu/desserts/dish[2]/price" />
9:  </xsl:template>
10:
11: </xsl:stylesheet>

Line 8 in Listing 3.10 tries to get the value of the price attribute of a dish element. That this approach doesn't work is obvious from the result in Listing 3.11.

Listing 3.11 Result from Applying Listing 3.10 to Listing 3.1

<?xml version="1.0" encoding="utf-8"?>
   Dessert of the Day:
   Chocolat Mousse
   Price:

The value-of element in Listing 3.10 doesn't yield a result. A gap appears in the result because no element matches the select expression. That is as it should be, because no price element exists. The dish element does, however, have a price attribute, which is what Listing 3.10 is supposed to select. What's wrong?

Nothing is wrong. You just need to tell the processor that it needs to match an attribute, not an element. You can tell the processor that you're looking for an attribute by adding the @ character in front of the name. So, if line 8 in Listing 3.10 is supposed to point to an attribute, the path expression should be /menu/desserts/dish[2]/@price, as shown in Listing 3.12. The result in Listing 3.13 is now correct.

Listing 3.12 Stylesheet Correctly Selecting an Attribute

1: <?xml version="1.0" encoding="UTF-8"?>
2: <xsl:stylesheet version="1.0"
3:  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:  <xsl:template match="/">
6:   Dessert of the Day:
7:   <xsl:value-of select="/menu/desserts/dish[2]" />
8:   Price: <xsl:value-of select="/menu/desserts/dish[2]/@price" />
9:  </xsl:template>
10:
11: </xsl:stylesheet>

Listing 3.13 Result from Applying Listing 3.12 to Listing 3.1

<?xml version="1.0" encoding="utf-8"?>
   Dessert of the Day:
   Chocolat Mousse
   Price: 5.95

Listing 3.12 produces the desired result. Because attributes don't have any child elements, you also know that no side effects will occur. The value of the attribute is always text.

NOTE

Attributes can have data types, but all are based on the text value. Data types will be thoroughly discussed on Day 10, "Working with Data Types."

Because attributes don't have side effects, they are much easier to work with. Also, because all attributes of an element need to have a different name, you have no trouble with matching multiple attributes (and getting only the value of the first). The only way you can get multiple attributes is to start working with selections based on a wildcard character.

Another point to consider is that attributes take less space in a document than elements. Elements have begin and end tags; an attribute doesn't need these tags. Because attributes have only a text value, a parser or processor can deal with them more quickly because it doesn't have to check for child elements. This is likely to have a positive effect on performance.

Beyond the Basics

Until now, the discussion has targeted single nodes wherever possible. In fact, the focus has been on how to avoid selections that yield more than one node. Although this information is very useful to get you started, it really limits your capabilities. Without creating complex expressions, you can already perform many tasks with some of the basic functionality XPath provides.

Using a Wildcard

Wildcard characters are common in most search-oriented functions and languages. XPath has only one wildcard character: *. You can use it only to match entire names of elements or attributes, so the expression a* does not match all elements starting with the letter a. This expression generates an error instead. Wildcards are useful when you want to drill deeper into the source XML, and the names of certain nodes (particularly parent nodes) don't matter. Listing 3.14 shows how to use a wildcard.

Listing 3.14 Stylesheet Using a Wildcard

1: <?xml version="1.0" encoding="UTF-8"?>
2: <xsl:stylesheet version="1.0"
3:  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:  <xsl:template match="/menu/*/dish">
6:   -<xsl:value-of select="text()" />
7:  </xsl:template>
8:
9: </xsl:stylesheet>

Line 5 in Listing 3.14 uses a wildcard character, so it doesn't matter whether the matched dish element is a child element of the appetizers, entrees, or desserts element. Line 6 just shows the value of the matched dish element. Listing 3.15 shows the result.

Listing 3.15 Result from Applying Listing 3.14 to Listing 3.1

<?xml version="1.0" encoding="utf-8"?>


   Crab Cakes

   Jumbo Prawns

   Smoked Salmon and Avocado Quesadilla

   Caesar Salad


   Grilled Salmon

   Seafood Pasta

   Linguini al Pesto

   Rack of Lamb

   Ribs and Wings


   Dame Blanche

   Chocolat Mousse

   Banana Split

In Listing 3.15, the result yields all the dish nodes, not just those that are child nodes of a particular node.

You can use this technique in all kinds of situations. Say that you've created a whitepaper or book using an XML document. Using a wildcard, you can select all the chapter and section headers to create a table of contents. If you don't want to get all the nodes, using just the wildcard doesn't solve your problem. However, just as with the path expressions you saw earlier, you can use predicates to refine the expression. That way, you have more control over what the wildcard actually matches. A simple example is shown in Listing 3.16.

Listing 3.16 Stylesheet Using Wildcards and Predicates

1: <?xml version="1.0" encoding="UTF-8"?>
2: <xsl:stylesheet version="1.0"
3:  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:  <xsl:template match="/">
6:   Dessert of the Day:
7:   <xsl:value-of select="/menu/*[3]/dish[2]" />
8:   Price: <xsl:value-of select="/menu/*[3]/dish[2]/@*[2]" />
9:  </xsl:template>
10:
11: </xsl:stylesheet>

Listing 3.16 yields the same result as Listing 3.12; the result is shown in Listing 3.13. Instead of addressing nodes by name, line 8 in Listing 3.16 uses several wildcards aided by position predicates. The desserts element is the third child element of the menu element. The /menu/*[3] section of the path expression tells the processor to take the third child element of the menu element, with no regard to the name of that element. That expression yields the desserts element, just as if it had been named. The attribute chosen is also based on a wildcard. In this case, the expression tells the processor to take the second attribute of the dish element, which is, of course, the price attribute.

Working with the Document Tree

What you've seen so far is quite rigid in utilizing the XML document tree. XPath can do much more, based on location paths, which are expressions that select a node or node-set relative to the context node. A location path consists of several parts. The path expressions you've seen so far often are specific cases of location paths, starting from the root node or current node (from a matching template). Location paths can, however, appear in other instances and as part of a predicate within a path expression. One part of a location path is actually a predicate, so you can have a location path with a predicate, containing a location path containing another predicate, and so on.

Another part of a location path that you are already familiar with is called a node test, which is the part of the location path that matches a certain node or nodes. This definition is clearer with an example. Consider the following location path:

/menu/*[3]/dish[2]/@*[2]

Here, menu, *, dish, and @* are node tests.

The last (or actually the first) part of a location path may not be familiar to you yet. This part, called an axis, is an expression specifying the relationship within the document tree between the selected nodes and the context node.

In the previous examples, you saw quite a few location paths. Not all of them contained axes, however. Well, they did, but the axes were included implicitly. Look at the following location path:

/menu/desserts/dish

This location path selects all the dish elements, which are child nodes of desserts nodes, which in turn are child nodes of the root element menu. If you write out that location path in full, it actually reads

/child::menu/child::desserts/child::dish

The axis and the node test are always separated by a double colon. The axis in front of the node test tells the processor where to look for a node or node-set. The node test tells the processor which nodes to actually match. Using the explicit location path isn't very useful for match templates. The location path only becomes lengthier and less readable. Also, you would not often use the child axis because it is included implicitly anyway.

Another axis you are already familiar with is the attribute axis. You are actually familiar with its shortcut, the @ character. In Listing 3.12, the following location path was used on line 8:

/menu/desserts/dish[2]/@price

You also can write the @price selection using the attribute axis, which would yield the following location path:

/menu/desserts/dish[2]/attribute::price

An axis that you haven't yet encountered but is quite clear is the parent axis. Yes, you guessed it: It returns the parent node of the current context. Listing 3.17 shows an example using the parent axis.

Listing 3.17 Stylesheet Using parent Axis

1: <?xml version="1.0" encoding="UTF-8"?>
2: <xsl:stylesheet version="1.0"
3:  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:  <xsl:template match="/"><xsl:apply-templates /></xsl:template>
6:
7:  <xsl:template match="/menu/appetizers/dish">
8:   <xsl:value-of select="parent::*/@title" />: <xsl:value-of select="." />
9:  </xsl:template>
10:
11:  <xsl:template match="/menu/entrees" />
12:  <xsl:template match="/menu/desserts" />
13:
14: </xsl:stylesheet>

Line 8 in Listing 3.17 uses the parent axis to select the title attribute of the parent element. This is the parent element of the current node, which is one of the dish elements in the appetizers element. Listing 3.18 shows the result.

Listing 3.18 Result from Applying Listing 3.17 to Listing 3.1

<?xml version="1.0" encoding="utf-8"?>

  Work up an Appetite: Crab Cakes
  Work up an Appetite: Jumbo Prawns
  Work up an Appetite: Smoked Salmon and Avocado Quesadilla
  Work up an Appetite: Caesar Salad

In Listing 3.18, the title attribute is inserted with every dish. This could also have been done with absolute addressing, but if there had been a separate template for the dish element, dishes in entrees or desserts could also match and the title would need to be different. In that case, relative addressing using the parent axis would be the only way out.

There is another way to specify any parent node. If you're familiar with the command prompt from DOS or Unix, it will look familiar. The location path

parent::*/@title

can also be written as

../@title

The latter example is much more compact and usable. If, however, the node test is not a wildcard, using this location path would not work. You would have to specify the parent axis explicitly, as well as the node that the node test needs to match.

Multilevel Axes

The axes discussed so far cover a single level in the XML document tree. They either go one level down, to child nodes, or one level up, to the parent node. Several axes operate on multiple levels. This does not mean, however, that such an axis returns a tree fragment because that wouldn't give added functionality. If that were the case, the parent and child axes would suffice. Each multilevel axis yields a node-set containing all the elements within that axis. The order in which the elements appear in the node-set depends on the axis. So, you can actually think of a multilevel axis as part of the XML document tree "flattened" into a set.

The best way to show you how these axes work is to go through some examples. The easiest axis to start with is ancestor, which is shown in Listing 3.19.

Listing 3.19 Stylesheet Using the Ancestor Axis

1: <?xml version="1.0" encoding="UTF-8"?>
2: <xsl:stylesheet version="1.0"
3:  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:  <xsl:template match="/menu/appetizers">
6:    <xsl:value-of select="dish[1]/ancestor::*[1]/@title" />
7:    <xsl:value-of select="dish[1]/ancestor::menu/entrees/@title" />
8:  </xsl:template>
9:
10:  <xsl:template match="/menu/entrees">
11:  <xsl:template match="/menu/desserts">
12:
13: </xsl:stylesheet>

All the action occurs in Lines 6 and 7 in Listing 3.19. Both lines first select the first child node of the appetizers element named dish. At that point, this element becomes the context node. Next, the ancestor axis tells the processor it wants to act on the ancestor nodes of the context node. The ancestor nodes are appetizers and menu. On line 6, the node test consists of a wildcard and predicate—in this case, pointing to the first ancestor node in the axis, which is the parent node appetizers. On line 7, a named node test specifies that the menu element is the element needed in this particular axis. This line could also have been written as ancestor::*[2] because that is the grandparent of the context node and, as such, the second node in the axis node-set ancestor.

Listing 3.20 Result from Applying Listing 3.19 to Listing 3.1

<?xml version="1.0" encoding="utf-8"?>

    Work up an Appetite
    Chow Time!

Listing 3.20 shows that Listing 3.19 first selects the title attribute of the appetizers element and then the title attribute of the entrees element.

Several more multilevel axes are available. All axes are listed in Table 3.1.

Table 3.1 Available Axes

Axis

Description

Self

The context node itself

child

All child nodes of the context node

parent

The parent node of the context node

ancestor

All ancestor nodes of the context node

ancestor-or-self

Same as ancestor, including the context node as the first node in the node-set

descendant

All descendant nodes of the context node, numbered depth first (for example, child 1, grandchild 1, child 2, grandchild 2, and so on)

descendant-or-self

Same as descendant, including the context node as the first node in the node-set

following-sibling

All sibling nodes that succeed the context node within the document tree

following

Same as following-sibling, but including their descendants, depth first (for example, sibling 1, child 1 of sibling 1, sibling 2, and so on)

preceding-sibling

All sibling nodes that precede the context node within the document tree

preceding

Same as preceding-sibling, but including their descendants, depth first (for example, sibling 1, child 1 of sibling 1, sibling 2, and so on)


Figure 3.5 shows a graphical representation of most axes in Table 3.1 to give you a better idea of what each axis listed actually selects.

Figure 3.5 Graphical representation of the axes in Table 3.1.

Something that is, strictly speaking, not an axis but fits nicely in this section is the // expression. It matches any location within the document tree. So, //dish matches any dish node within the document. Listing 3.21 shows this expression in action.

Listing 3.21 Stylesheet Using // to Get All Nodes

1: <?xml version="1.0" encoding="UTF-8"?>
2: <xsl:stylesheet version="1.0"
3:  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5:  <xsl:template match="//dish">
6:    <xsl:value-of select="text()" />
7:  </xsl:template>
8:
9: </xsl:stylesheet>

Listing 3.21 yields the same result as Listing 3.14 because line 5 uses // to match all nodes in the document from which the dish nodes are selected.

A common mistake is to think that //dish[6] will yield the sixth dish element within the document. Unfortunately, because of precedence rules, this expression will yield no element at all. The processor will look for a sixth element in each of the parent contexts. Unfortunately, there is none because appetizers contains only four dish elements; entrees, only five; and desserts, only three. So how do you solve this problem? You can use parentheses to override the default precedence. Therefore, (//dish)[6] would yield the sixth element (the Seafood Pasta).

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020