Chapter 8. XPath 2.0 Expressions and Operators

Creating Primary Expressions

The most basic expression type is the primary expression type. This type can be one of these:

  • A literal

  • A variable

  • A function call

  • A context item

  • A parenthesized expression, which is used to control precedence of operators

  • A comment

To understand these in detail, we'll take a look at them one by one.

Literals

A literal is just a value that is of an atomic type. As we saw in Chapter 7, “What's New in XPath 2.0,” this means a value of a primitive simple type defined by the XML Schema specification, or a value of a type derived from them by restriction in a schema.

XPath 2.0 has built-in support for two types of literals—numeric literals and string literals. You can create a string literal simply by enclosing a string of characters in quotes, and numeric literals simply by writing the numeric value. You can see a simple example in ch08_01.xsl (Listing 8.1), which uses a string literal as an XPath expression.

Example 8.1. An XSLT Example Using an XPath Literal (ch08_01.xsl)

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xsl:template match="/">
        <xsl:value-of select="'No worries!'"/>
    </xsl:template>

</xsl:stylesheet>

A string literal's value is an xs:string atomic type. You can simply enclose a string of characters in quotes, but be careful about nested quotes. For example, this literal is okay: “This is fine.” You can also use single quotes like this: 'This is also fine.' But what if you want to use quotation marks inside a string literal? In that case, you can nest single and double quotes, like this:

"I said, 'This literal is OK.'"

You can also use double quotation marks to indicate quoted text. For example, this string literal works just as the previous one did, except that the internal quoted text is delimited by two double quotes:

"I said, ""This literal is OK."""

Doubling single quotation marks works the same way:

'I said, ''This literal is OK.'''

By default, numeric literals that don't contain a “.” and contain no “e” or “E” (used to specify exponents), are of type xs:integer. For example, here are some integer numeric literals:

345
1
-9999

On the other hand, if your numeric value includes a “.”, but no “e” or “E”, XPath 2.0 assumes the literal is of the xs:decimal data type. Here are a few examples:

3.14159
-1.000
2.7128

If you include an “e” or an “E” character, XPath 2.0 assumes your numeric literal is an xs:double type. Here are a few examples:

3.14159E10
55.00e45
1.9e-5

Besides string and numeric literals, you can also use Boolean values, representing them with the built-in functions true() and false().

You can also create literals of any of the XML schema types using their constructors. We saw an example of how that works in Chapter 7, where we created an xs:date literal:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xsl:template match="/">
        <xsl:value-of select="xs:date('2004-09-02')"/>
    </xsl:template>

</xsl:stylesheet>

Here are a few other examples of creating literals based on XML schema types using the appropriate constructors:

xs:integer(45)
xs:decimal(3.14159)
xs:string("No worries!")

USING THE cast EXPRESSION

You can also create literals of a desired data type using the cast expression, which we'll see later in this chapter.

Variables

Variables are also expressions in XPath 2.0—the value of the expression is the value stored in the variable. In XPath 2.0, variables are valid XML names (that is, an XML QName), preceded by a $.

There are two sources of variables in XPath 2.0—the host language (such as XSLT), and those variables that you can define in XPath itself. For example, we've seen in Chapter 7 that you can create variables in XSLT using the <xsl:variable> element, and use them in XPath 2.0 like this:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:variable name="rightNow" select="current-dateTime()" />

    <xsl:template match="/">
        The date and time is:
        <xsl:value-of select="$rightNow"/>
    </xsl:template>

</xsl:stylesheet>

You can also use support for variables in XPath 2.0, as in these for and some expressions:

for $variable in /planets/planet return $variable/mass
some $variable in /planets/planet[1]/name satisfies $variable = "Mars"

Parenthesized Expressions

When you're using multiple operators, such as multiple arithmetic operators, there can be some confusion about which operator is applied first. For example, what does 1 + 2 * 3 equal—3 * 3 or 1 + 6? It turns out that the multiplication operator is evaluated first, so 1 + 2 * 3 = 1 + 6 = 7.

UNDERSTANDING SCOPE

As in various programming languages, variables in XPath 2.0 also have scope, which is the region in which the XPath processor can access them. For example, in the for expression in the preceding code, the variable named $variable is in scope only inside the body of the return clause—outside that body, you can't use this variable. In the some expression in the preceding code, $variable is in scope in the satisifies clause's body.

On the other hand, if you wanted to add the 1 and 2 before multiplying the result by 3, you could use parentheses to indicate the order of execution you want:

(1 + 2) * 3

In XPath 2.0, parenthesized expressions like these are valid. (And don't forget that you can use an empty set of parentheses—()—to represent an empty sequence.)

Function Calls

Function calls are also considered expressions in XPath 2.0, and their value is simply the value returned by the function. For example, we took a look at the XPath 2.0 built-in max function in Chapter 7:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="planets">
        <HTML>
            <HEAD>
                <TITLE>
                    The Largest Planetary Radius
                </TITLE>
            </HEAD>

            <BODY>
                <H1>
                    The Largest Planetary Radius
                </H1>
                <BR/>
                The largest planetary radius is
                <xsl:value-of select="max(//planet/radius)"/>
                miles.
            </BODY>

        </HTML>
    </xsl:template>

</xsl:stylesheet>

Here, the value of the function call is the sequence it returns.

Note that you can pass not only atomic values to functions, but also sequences. For example, this function call passes the values 4, 5, and 6 to a function:

function(4, 5, 6)

But this example passes a sequence consisting of 4 and 5, and then a value of 6:

function((4, 5), 6)

Context Item Expressions

The context item expression is simply a dot, “.”, and as in XPath 1.0, it stands for the current context item. This can be a context node (the node from which evaluation of an expression starts), as in the path expression //planet[count(./name) > 1].

In XPath 2.0, context items can also be atomic values, as in this expression: (1 to 100)[. mod 10 eq 0], which returns the sequence (10, 20, 30, 40, 50, 60, 70, 80, 90, 100).

Creating Arithmetic Expressions

Besides primary expressions, XPath 2.0 also supports arithmetic operators for addition, subtraction, multiplication, division, and modulus. These operators are represented this way (note that instead of using the / symbol for division, which can be interpreted as markup, XPath 2.0 uses the div operator):

  • +—. Addition

  • -—. Subtraction and Negation

  • *—. Multiplication

  • div—. Division

  • idiv—. Integer division

  • mod—. Modulus

USING THE SUBTRACTION OPERATOR

In XPath 2.0, you must precede a subtraction operator with a space, because “-” is a legal name character. In other words, x-y can be interpreted as a name, whereas x - y is an expression involving a subtraction operation.

The idiv operator requires its operands to be of type xs:integer and returns a result of type xs:integer, rounded toward zero. And the mod operator returns the remainder after a division (for example, 16 mod 3 is 1).

Here are some examples of arithmetic expressions:

  • 4 * 2 returns 8

  • 33 + 11 returns 44

  • -5 div 2 returns –2.5

  • -5 idiv 2 returns –2

  • $temp + 12 returns 72 if $temp holds 60

  • -(20 + 6) returns –26

SUBTRACTING DATE VALUES

In XPath 2.0, if you subtract two date values, the result is of the xdt:dayTimeDuration type.

Creating Path Expressions

As in XPath 1.0, you can use a path expression to locate nodes. In fact, XPath 2.0 carries over just about all the same syntax for path expressions from XPath 1.0, although, of course, node-sets are now called sequences and there are other changes, such as deprecating (making obsolete) the namespace axis.

As in XPath 1.0, path expressions are made up of location steps. In turn, location steps are made up of an axis, a node test, and zero or more predicates:

axis :: node-test [predicate]*

If you start a location path with / or //, the location path is an absolute location path because you're a specifying the path from the root node of the XML document. Otherwise, the location path is relative, starting with the context node.

XPath 2.0 Axes

Each XPath 2.0 path expression must specify an axis (or use the default child axis), as in this location path: /library/book/title[2]/text. The XPath 2.0 axes are the same as the XPath 1.0 axes.

Note in particular that the namespace axis is now deprecated in XPath 2.0. That means that it's in a kind of limbo, preparatory to being phased out. Whether or not the software package you're using supports the namespace axis is now up to the package itself—it no longer has to.

XPath 2.0 Node Tests

When you use an axis in a location step, you're telling XPath 2.0 where to look and identifying a set of nodes. As in XPath 1.0, a node test tells XPath 2.0 which of the nodes in that set you're interested in.

There are two ways of creating node tests in XPath 2.0. You can use node names as node tests, along with a wildcard character, *, as in XPath 1.0. Or you can use “kind” tests like comment(), text(), and so on, as also in XPath 1.0. Here's an overview of the kinds of node tests you can use in XPath 2.0—note that element(), attribute(), and document-node() are new in XPath 2.0:

  • A name matches a node with that name (for example, planet will match a <planet> element).

  • The * wildcard character matches any node of the principal node kind—elements, attributes, or namespaces. For example, child::* will select all element children of the context node, and attribute::* will select all attributes of the context node. You can also use * with the namespace axis.

  • The comment() node test selects comment nodes.

  • The node() node test selects any type of node.

  • The processing-instruction() node test selects a processing instruction node. You can specify the name of the processing instruction to select in the parentheses.

  • The text() node test selects a text node.

  • The element() node test selects elements.

  • The attribute() node test selects attributes.

In XPath 2.0, you can pass parameters to the kind node tests element() and attribute(). Here are some examples (for more on type annotations, see the discussion on them in Chapter 7):

  • element(planet) matches any element node whose name is planet and whose type annotation conforms to the schema declaration for a <planet> element.

  • element(planet, *) matches any element node whose name is planet without any restriction on type annotation.

  • element(planet, giant) matches any element node whose name is planet, and whose type annotation is giant or is derived from giant.

  • element(*, giant) matches any element node whose type annotation is giant, regardless of its name.

  • element(solarsystem/planet) matches any element node whose name and type annotation conform to the schema declaration of a <planet> element in a <solarsystem> element.

  • attribute() matches any attribute node.

  • attribute(language, *) matches any attribute whose name is language, regardless of its type annotation.

  • attribute(*, xs:decimal) matches any attribute whose type annotation is xs:decimal or derived from xs:decimal.

  • document-node() matches any document node.

  • document-node(element(planet)) matches any document node whose content consists of a single element node that satisfies the element(planet) node test.

XPath 2.0 Predicates

As in XPath 1.0, the next part of a location step, which follows the node text, is the predicate. A location step doesn't need a predicate, but using predicates, you can filter the nodes you want to locate even more.

Predicates are where you use the many XPath 2.0 functions when you want to use them in path expressions. This works as it does in XPath 1.0; for example, in the location step child::planet[position() = 2], the predicate is position() = 2. This means that the value the built-in XPath function position() returns must indicate that this is the second <planet> child in order for the location step to match. As in XPath 1.0, this location step can also be abbreviated as planet[2].

XPath 2.0 Abbreviated Syntax

The rules for abbreviated syntax in XPath 2.0 are the same as in XPath 1.0 (technically speaking, . is not actually an abbreviation—it's the context node item, as discussed earlier.):

  • self::node() can be abbreviated as.

  • parent::node() can be abbreviated as ..

  • child::nodename can be abbreviated as nodename

  • attribute::nodename can be abbreviated as @nodename

  • /descendant-or-self::node()/ can be abbreviated as //

As you know from XPath 1.0, you can also abbreviate position expressions like [position() = 6] as [6]. That's all there is to abbreviated syntax. The next type of XPath 2.0 expression we'll take a look at is sequence expressions.

Creating Sequence Expressions

As we've seen in Chapter 7, you can create sequence expressions with the comma (,) operator. In XPath 2.0, the comma operator evaluates each of its operands and joins the results into a sequence.

You can use empty parentheses to indicate an empty sequence. Also note that sequences can never be nested—for example, combining the values 4, (5, 6), into a single sequence results in the sequence (4, 5, 6). Sequences can contain nodes or atomic values, or a mix.

Sequences may contain duplicate values or nodes. When you create a new sequence by concatenating two or more input sequences, the new sequence contains all the items in the original sequences.

We'll start our work on sequence expressions by seeing how to create sequences with them.

Creating Sequences

Here are a few examples; this sequence expression creates a sequence of six integers:

(9, 10, 11, 12, 13, 14)

In this case, we're creating a new sequence from the sequences 1, (2, 3), ()—that is, an empty sequence—and (4, 5, 6):

(1, (2, 3), (), 4, 5, 6))

This expression gives you the following sequence:

1, 2, 3, 4, 5, 6

Here's how you could create a sequence made up of all the <name> children of the context node, followed by all the <mass> children:

(name, mass)

You can also use variables or other expressions when creating sequences, like this:

($temperature, 3 * 6)

If $temperature holds 68, this example gives you this sequence:

(68, 18)

You can also use the range operator, as mentioned in Chapter 7, to create a sequence of integers. Here's an example:

(1 to 5)

This sequence expression creates the following sequence:

(1, 2, 3, 4, 5)

You can also use the range operator inside a sequence expression, like this:

(1, 2 to 5)

Here's the result:

1, 2, 3, 4, 5

What if you were to make the start and end of the range the same value by mistake? For example, how is XPath 2.0 supposed to handle this?:

9999 to 9999

In this case, the result is a singleton sequence with just one item, 9999.

Combining Sequences

XPath 2.0 also gives you a set of operators to work with sequences, as we saw in the overview in Chapter 7. We'll take a look at these operators—union, intersect, and except—which create sequence expressions, next.

EXCLUDING DUPLICATES

The union, intersect, and except operators return their results as sequences in document order, without any duplicate items in those sequences.

The union Operator

The union operator takes two node sequences as operands and returns a sequence containing all the nodes that occur in either of the original sequences. This operator works something like the logical or operator in other languages. The union operator is identical to the | operator.

Here are a few examples, where a, b, c, d, and e are nodes:

a, b, union c, d, e

This expression gives you

a, b, c, d, e

On the other hand, duplicate items do not appear in the resulting sequence. This expression

a, b, c union c, d, e

gives you

a, b, c, d, e

The intersect Operator

The intersect operator takes two node sequences as operands and returns a sequence containing all the nodes that occur in both operands. This operator works like the logical and operator in other languages.

Here are a few examples; in this expression, both the nodes b and c are common to both sequence operands:

a, b, c intersect b, c, d

And here's the result:

b, c

This sequence combination expression

d, e, f intersect b, c, d

gives you just a singleton sequence:

d

If you try to find the intersection of two sequences that have no items in common, like this:

a, b intersect c, d

the result will be an empty sequence, ().

The except Operator

The except operator takes two node sequences as operands and returns a sequence containing all the nodes that occur in the first operand but not in the second operand.

Here's an example:

a, b, c except c

gives you

a, b

Here's another example:

a, b, c, d except c, d, e

gives you

a, b

This expression

a, b, c except d, e, f

gives you

a, b, c

FUNCTIONS THAT SUPPORT INDEXED ACCESS

Besides the sequence operators we're discussing here that are evaluated as XPath expressions, there's also a set of functions that support indexed access to items or subsequences of a sequence, indexed insertion or removal of items in a sequence, and removal of duplicate values or nodes from a sequence. They're coming up in Chapter 12, “XPath 2.0 Node and Sequence Functions.”

And this expression

a, b, c except a, b, c, d, e

gives you an empty sequence, ().

Creating Comparison Expressions

Comparison expressions return the result of comparing two values. XPath 2.0 actually supports four kinds of comparison expressions: value comparisons, general comparisons, node comparisons, and order comparisons.

We'll take a look at them all here, starting with value and general comparisons. These two types of comparisons have been added so that XPath 2.0 can support comparisons with both single values and with sequences.

Value Comparisons

You use the value comparison operators when you're working with atomic values. Here they are:

  • eq—. Equals

  • ne—. Not equals

  • lt—. Less than

  • le—. Less than or equal to

  • gt—. Greater than

  • ge—. Greater than or equal to

These operators give you a result of true or false. Here's an example—say that $temperature holds the value 68; in that case, this expression would evaluate to true:

$temperature lt 72

This comparison is true only if $planet has a single <name> child element and its value is “Venus”:

$planet/name eq "Venus"

General Comparisons

You can use general comparisons on sequences (including singleton sequences). Here are the general comparisons:

  • =—. Equals

  • !=—. Not equals

  • <—. Less than

  • <=—. Less than or equal to

  • >—. Greater than

  • >=—. Greater than or equal to

ESCAPING RULES

As in XPath 1.0, when you use XPath expressions inside an XML document, the XML escaping rules for special characters should be followed. For example, “<” should be written as “&lt;”.

You use these operators on sequences. (What actually happens is that a value comparison operator, eq, ne, lt, le, gt, or ge—depending on which corresponding general comparison operator was used—is used to compare individual items in the sequence.) The software evaluating a general comparison usually will return a value of true as soon as it finds an item in the first operand and an item in the second operand for which the value comparison is true.

Here's an example pointing out how these operators deal with sequences, not just individual values. In this case, we're comparing two sequences, (1, 2) and (2, 3) with the general equality operator:

(1, 2) = (2, 3)

In this case, the result is true because the value 2 appears in both sequences.

Here, however, the result is false, because there is no value in the first sequence that is equal to a value in the second:

(1, 2) = (3, 4)

As with value comparisons, this comparison is true only if $planet has a single <name> child element and its value is “Venus”:

$planet/name = "Venus"

Node Comparisons

You can use node comparison expressions to compare nodes using the is operator.

A comparison expression with the is operator is true if the two operands are nodes that are identical; otherwise it is false.

For example, this comparison is true only if the left and right sides each evaluate to exactly the same single node:

//planet[name="Venus"] is //planet[days=116.75]

Order Comparisons

You use order comparison expressions to compare the order of nodes; both operands here must be either a single node or an empty sequence (if either operand is an empty sequence, the result of the comparison is an empty sequence). Here are the order comparison operators:

  • <<—. Earlier than

  • >>—. Later than

Using the << operator returns true if the first operand node is earlier than the second operand node in document order; otherwise it returns false. Using the >> operator returns true if the first operand node is later than the second operand node in document order; otherwise it returns false.

Here's an example:

//planet[name="Venus"] << //planet[days=116.75]

This example returns true if the node matched by //planet[name="Venus"] comes earlier in document order than the node matched by //planet[days=116.75].

Creating Logical Expressions

A logical expression uses logical operators and is a compound expression. Unless there's an error, its value is always either true or false. Here are the logical operators:

  • and—. Performs a logical and operation

  • or—. Performs a logical or operation

The and operator lets you connect two Boolean operands and returns true if both operands are true, and false otherwise. The or operator lets you connect two logical operands and returns true if either operand is true, and false otherwise.

Here's an example. Say that $temperature holds a value of 72; in that case, this example returns a value of true:

$temperature < 80 and $temperature > 60

And this expression also returns true, because one logical operand ($temperature > 60) is true:

$temperature > 80 or $temperature > 60

THE not FUNCTION

XPath 2.0 also has a function named not(), which reverses the Boolean value of the value you pass to it. For example, if $temperature holds a value of 72, then $temperature = 72 is true, and not($temperature = 72) is false. More on this function is coming up in Chapter 11, “XPath 2.0 Boolean, QName, and Date Functions.”

This expression returns false:

$temperature > 80 and $temperature > 60

Creating for Expressions

XPath provides the for expression so that you can iterate over data. Here's how the for expression works in general:

for variable in sequence return expression

Here, the variable is called the range variable, the value of the expression that follows the in keyword is called the input sequence, and the expression that follows the return keyword is called the return expression.

The result of the for expression is obtained by evaluating the return expression once for each item in the input sequence. The resulting sequence is returned (if multiple sequences are generated, they are concatenated).

You can see an example in ch08_02.xsl, where we're using a for expression to create a sequence of all the planet names in our planetary data XML document:

for $variable in //planet return $variable/name

To display our results using an XPath 2.0 style sheet, we'll use the <xsl:value-of> element to insert the result sequence of names into the output. That means we have to use this element's separator attribute to indicate what text we want inserted between items in the sequence—if you don't use this attribute, you'll only get the first item in the sequence. You can see what the XSLT 2.0 style sheet looks like in ch08_02.xsl (Listing 8.2).

Example 8.2. An XSLT Example Using the for Expression (ch08_02.xsl)

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xsl:template match="/">
        <xsl:value-of select="for $variable in //planet return $variable/name"
            separator=", "/>
    </xsl:template>

</xsl:stylesheet>

And here's the result when we use Saxon to apply the ch08_02.xsl style sheet to our planetary data document:

C:Saxon>java net.sf.saxon.Transform ch02_01.xml ch08_02.xsl
<?xml version="1.0" encoding="UTF-8"?>
Mercury, Venus, Earth

As you can see, we do indeed get all three planetary names this way. A for expression can also use multiple variables. For example, this expression uses two variables at once:

for $x in (1, 2)
    $y in (3, 4)
return ($x * $y)

The result of this for expression is the sequence (3, 4, 6, 8).

Creating Conditional Expressions

As we saw in the overview in Chapter 7, XPath 2.0 supports a conditional expression that uses the keywords if, then, and else. Here's what this expression, also called the if expression, looks like in its general form:

if expression then then-expression else else-expression

The expression following the if keyword is called the test expression, and the expressions following the then and else keywords are called the then-expression and else-expression, respectively.

If the value of the test expression is true, the value of the then-expression is returned. If the Boolean value of the test expression is false, the value of the else-expression is returned.

Here's an example using a conditional expression in an XSLT 2.0 stylesheet. In this case, we'll declare an XSLT variable named $temperature that holds the value 80:

<xsl:variable name="temperature" select="80" />

Now we'll test that new variable's value in a conditional expression, evaluating to the text “Too hot” if the temperature is above 72, and “OK” otherwise:

if ($temperature > 72) then 'Too hot' else 'OK'

You can see what the complete XSLT 2.0 stylesheet looks like in ch08_03.xsl (Listing 8.3).

Example 8.3. An XSLT Example Using the if Expression (ch08_03.xsl)

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:variable name="temperature" select="80" />

    <xsl:template match="/">
       <xsl:value-of select="if ($temperature > 72) then 'Too hot' else 'OK'"/>
    </xsl:template>

</xsl:stylesheet>

And here's the result you get when you use Saxon:

<?xml version="1.0" encoding="UTF-8"?>
Too hot

You can use any kind of a test expression, as long as it evaluates to a true/false value. For example, in this case, we're checking which of two planets has the greater mass, and returning the one that does:

if (//planet[1]/mass > //planet[2]/mass)
    then //planet[1]
    else //planet[2]

You don't have to compare values either; you can simply test for the existence of an item, as here, where we're testing if a <planet> element has a <name> child element:

if (//planet[1]/name)
    then //planet[1]/name
    else //planet[2]/name

You can also nest if expressions, as in this example:

if ($fruit eq "apple")
then "It's an apple."
else if ($fruit eq "orange")
then "It's an orange."
else "I have no idea what this is."

Creating Quantified Expressions

Quantified expressions use the some and every keywords to perform checks on the items in a sequence. You can use the some keyword to ensure that at least one of the items in the sequence satisfies a particular criterion, and the every keyword to make sure that every item in the sequence satisfies some criterion.

Using the some Expression

Here's how you use the some quantified expression:

some in-claus(es) statisfies test-expression

A quantified expression like this starts with the some keyword, followed by one or more in-clauses, followed by the keyword satisfies, followed by a test-expression. What this expression does is to let you test if at least one item in the in-clause(s) satisfies the test expression.

Let's take a look at a few examples to make this clear. This expression is true if at least one of the <planet> elements in the document has a <name> child element:

some $planet in //planet satisfies $planet/name

Here's an example that tests if at least one <planet> element has a language attribute:

some $planet in //planet satisfies $planet/@language

In this way, you can use quantified expressions to test for the existence of items like elements and attributes.

You can also test logical conditions, as here, where we're making sure that at least one planet has a mass greater than 1.5:

some $planet in //planet satisfies ($planet/mass > 1.5)

Here's another example:

some $planet in //planet satisfies ($planet/name = "Mars")

You can also use multiple in-clauses in a some expression. Here's an example, where we're testing the product of numbers:

some $operand1 in (4, 5, 6), $operand2 in (7, 8, 9)
     satisfies $operand1 * $operand2 = 40

TERMINATING A some EXPRESSION

Although this is implementation-specific, the software may terminate a some expression as soon as it is able to satisfy the test expression, without evaluating all possible values.

In this case, all possible combinations of the items in the in-clauses are tested—nine combinations in all. That is, 4 * 7 is tested, then 4 * 8, 4 * 9, then 5 * 7, 5 * 8, and so on.

Using the every Keyword

Here's how you use the every quantified expression:

every in-claus(es) statifies test-expression

This quantified expression starts with the every keyword, followed by one or more in-clauses, followed by the keyword satisfies, followed by a test-expression. This expression lets you test if every item in the in-clause(s) satisfies the test expression.

Here are a few examples. This expression is true if every one of the <planet> elements in a document has a <name> child element:

every $planet in //planet satisfies $planet/name

As with the some expression, you can either test for the existence of an item this way, or you can test a logical condition. This every expression tests whether planet's <day> value is greater than or equal to one:

every $planet in //planet satisfies ($planet/day ge 1)

And you can also use multiple in-clauses with the every expression, just as you can with some, as in this example:

every $operand1 in (4, 5, 6), $operand2 in (7, 8, 9)
     satisfies $operand1 * $operand2 > 27

You can see an example where we're using every in an XSLT 2.0 stylesheet in ch08_04.xsl (Listing 8.4). In this case, we're testing three temperatures to see if they're all above 72, and if so, we'll display the message “Too hot”.

Example 8.4. An XSLT example Using the every Expression (ch08_04.xsl)

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:variable name="t1" select="80" />
<xsl:variable name="t2" select="90" />
<xsl:variable name="t3" select="100" />

    <xsl:template match="/">
        <xsl:value-of select="if (every $temperature in ($t1, $t2, $t3)
            satisfies $temperature > 72) then 'Too hot' else 'OK'"/>
    </xsl:template>
</xsl:stylesheet>

Here's the result:

<?xml version="1.0" encoding="UTF-8"?>
Too hot

Creating Expressions That Work on Types

XPath 2.0 emphasizes data types, and you can create XPath 2.0 expressions that work expressly with types using these keywords:

  • instance of—. Check an item's data type (works with any simple or complex type).

  • cast—. Change an item's data type.

  • castable—. Check whether an item's data type may be cast.

  • treat—. Treat an item as if it were a new data type for the purposes of evaluation (but don't actually change the item's data type). (The treat expression works with any simple or complex type.)

We'll take a look at how these expressions work now.

instance of

The instance of operator is a Boolean operator that lets you test the type of an operand. Here's how you use it in an expression, where operand2 is a simple or complex type:

operand1 instance of operand2

This expression returns true if operand1 is of the data type operand2, and false otherwise. The type you give in operand2 can be fairly general—it can be an atomic type like xs:integer, a kind test like element() or node(), the keyword empty, or an empty sequence like this: (). It can also be the xdt:anyAtomicType type, which, as noted in Chapter 7, is an abstract type that you can't create variables of directly. If you use the xdt:anyAtomicType type with the instance of operator, you're saying that you're testing for any of the atomic types.

Using the instance of expression, you can test the data type of various items; for example, this expression returns true because 26 is an integer:

26 instance of xs:integer

Similarly, if $variable contains an integer value, this expression will return true:

$variable instance of xs:integer

TESTING xs:integer AGAINST THE xs:decimal TYPE

Actually, testing an xs:integer value against the xs:decimal type will return true because in XML schemas, the xs:integer type is derived by restriction from xs:decimal.

Here's an example that checks if 3.1415 is of type xs:decimal:

3.1415 instance of xs:decimal

Here's an example that lets you test the context item to see if it's an element:

. instance of element()

Instance of is very useful when you are working with schema-validated nodes and need to examine their runtime type.

cast

Because XPath 2.0 implements strong typing, it's sometimes necessary to convert values from one data type to another. You can use a cast expression to change an item's data type to another data type. You can use a cast expression like this:

source cast as target-type

Here, source is cast to a new data type, the target-type. In this case, the data type of source is actually changed to the target-type, if that cast is possible.

USING CONSTRUCTOR FUNCTIONS

Bear in mind that you can also use the constructor functions that come with various types to cast data from one type to another. For example, to cast an xs:string into an xs:date, you can use the xs:date constructor function to create a new xs:date value like this: xs:date("2005-03-02").

Here are a few examples showing how to use cast:

"2004-09-02" cast as xs:date
$variable cast as xs:integer
$temperature cast as xs:decimal

When can you use cast? Here's the list:

  • cast expressions are supported for the combinations of input type and target type listed in the table at http://www.w3.org/TR/xquery-operators/#casting. This is the definitive place to look for cast operations. For example, you can find there that you can cast from xs:double to xs:decimal.

  • cast expressions are supported if the input type is a derived atomic type and the target type is a supertype of the input type. For example, if the zipcode type is derived by restriction from xs:integer, a value of type zipcode can be cast into the type xs:integer.

  • cast expressions are supported if the target type is a derived atomic type and the input type is xs:string or xdt:untypedAtomic.

  • cast expressions are supported if the target type is a derived atomic type and the input type is a supertype of the target type. The resulting value is the same as the input value, but with a different type.

These rules can get pretty involved—how can you be sure the cast you're about to attempt is legal? Luckily, there's a fairly easy answer to that—you can use a castable expression to check if a cast is legal.

castable

The castable expression lets you test if an item may be cast to a specific type, and it returns a true/false answer. Here's how you use this expression:

source castable as target-type

This expression is true if source may be cast to target-type. Here's an example where we're checking whether $fruit may be cast to the type apple, and if not, whether it can be cast to the type orange:

if ($fruit castable as apple)
then $fruit cast as apple
else if ($fruit castable as orange)
then $fruit cast as orange
else $fruit cast as xs:string

treat

The treat expression is much like the cast expression, except that, unlike cast, it doesn't change the type of its operand. It acts like an assertion, checking the type of an expression. Here's how you use the treat operator in an expression:

source treat as target-type

This expression asserts that source is of the target-type data type. Otherwise, this expression returns an error.

Here's an example. In this case, the original type of $number might be number. Say that another type, ZIP, is derived from that type; in that case, this expression will be of the ZIP type when evaluated:

$number treat as ZIP

This expression also succeeds if the type of $number is ZIP. In other words, the treat expression acts much like an assertion, which succeeds if $number is of type ZIP or of a type derived from ZIP.

In Brief

  • Primary expressions can be a literal, a variable, a function call, a context item, a comment, or a parenthesized expression.

  • Besides the primary expressions, you can also use the arithmetic operators +, -, *, div, idiv, and mod. These operators perform addition, subtraction, multiplication, division, integer division, and modulus, respectively.

  • You can also create path expressions in XPath 2.0. XPath 2.0 path expressions are much the same as they are in XPath 1.0, with some exceptions, such as the deprecation of the namespace axis, and some additions, such as new node tests.

  • You can also create sequence expressions in XPath 2.0 that return sequences using the comma operator, and combine sequences with the union, intersect, and except operators.

  • XPath 2.0 also supports a number of comparison operators: eq, ne, lt, le, gt, and ge for comparisons of single values, and =, !=, <, <=, >, and >= to work with sequences. Node comparisons with is let you compare nodes. And the order comparisons << and >> let you determine the order of nodes.

  • XPath 2.0 logical expressions are supported with the and and or logical operators. These operators let you connect logical operands.

  • The for expression lets you create a loop to iterate over your data. This expression works much like the for statement in various programming languages, and supports the use of variables. The if expression lets you create conditional statements that let you test an expression's value and branch accordingly.

  • The quantified expressions, some and every, let you perform tests on the items in a sequence. The some expression tests whether at least one item in a sequence or sequences satisfies a particular expression, and the every expression tests whether every item in the sequence or sequences satisfies a test expression.

  • XPath 2.0 also contains expressions that deal with types—instance of to check an item's type, cast to change an item's data type, castable to check whether an item may be cast to a particular new type, and treat to treat an item as if it were of a different data type without actually changing the item's data type.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.134.78.106