There are plenty of functions that work with sequences; here's an overview:
Sequences are new in XPath 2.0, and as you can see here, there's a rich set of functions to work with them. We'll take this list apart, function by function, in the remainder of this chapter, starting with the fn:zero-or-one function. The fn:zero-or-one FunctionThis function returns $srcval if it is a sequence that holds zero or one items only. Here's how it works: fn:zero-or-one( $srcval as item*) as item? This function does not handle the case where you've passed a sequence with more than zero or one items gracefully. Instead, it causes an error with this text: "fn:zero-or-one called with a sequence containing more than one item". The fn:one-or-more FunctionThis function returns $srcval if it is a sequence that holds one or more items only. Here's how you use this function: fn:one-or-more( $srcval as item*) as item+ This function does not handle the case where you've passed a sequence with zero items well; in this case, it causes an error with this text: "fn:one-or-more called with a sequence containing zero items". The fn:exactly-one FunctionThis function returns $srcval if it contains exactly one item: fn:exactly-one( $srcval as item*) as item If you call this function with a sequence containing zero or more than one item, you'll get an error with the text "fn:exactly-one called with a sequence containing zero or more than one item".
The fn:boolean FunctionThis function returns the effective Boolean value of a sequence: fn:boolean( $srcval as item*) as xs:boolean This function returns false if $srcval is the empty sequence. If $srcval is an atomic value, it returns false if $srcval is the singleton xs:boolean value false , "", a numeric value equal to zero, a singleton xs:double , or an xs:float value that is NaN. Otherwise, this function returns a value of true . The fn:index-of FunctionThis function returns a sequence of positive integers giving the position(s) in a sequence of an item. Here's how you can use fn:index-of : fn:index-of( $seq as xs:anyAtomicType*, $srchParam as xs:anyAtomicType) as xs:integer* fn:index-of( $seq as xs:anyAtomicType*, $srchParam as xs:anyAtomicType, $collation as xs:string) as xs:integer* In this case, $seq is a sequence to search, $srchParam is the item you're searching for, and $collation represents an (optional) collation. This function lets you search sequences for multiple matcheshere are a few examples: fn:index-of((2, 3, 4), 2) returns 1. fn:index-of((2, 3, 4), 3) returns 2. fn:index-of((2, 3, 4), 5) returns (). fn:index-of((2, 3, 3, 4), 3) returns (2, 3). fn:index-of((2, 3, 3, 3, 4), 3) returns (2, 3, 4). The fn:empty FunctionThis function tests for the empty sequence: fn:empty( $srcval as item*) as xs:boolean If $srcval is the empty sequence, this function returns true ; otherwise, this function returns false . For example, fn:empty(()) returns true . The fn:exists FunctionThe fn:exists function returns true if you pass it a sequence that is not the empty sequence, and false otherwise. Here's how you use it: fn:exists( $srcval as item*) as xs:boolean Here are a few examples: fn:exists(()) returns false. fn:exists(1) returns true. fn:exists((1, 2, 3)) returns true. This function is a useful and quick one to make sure you're not dealing with an empty sequence. The fn:distinct-values FunctionYou use fn:distinct-values to strip duplicate values from a general sequence: fn:distinct-values( $srcval as xs:anyAtomicType*) as xs:anyAtomicType* fn:distinct-values( $srcval as xs:anyAtomicType*, $collation as xs:string) as xs:anyAtomicType* Note that you can specify a collation with this function if you want to. Here's an example; in this case, we're going to extract the distinct values from the sequence (1, 2, 2, 3) using fn:distinct-values , as you can see in ch12_04.xsl (Listing 12.4). Listing 12.4 Using fn:distinct-values ( ch12_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:template match="/"> Here are the distinct values: <xsl:value-of select="distinct-values((1, 2, 2, 3))" separator=", "/> </xsl:template> </xsl:stylesheet> And here's the resultas you can see, we've been able to get the distinct values from the sequence: <?xml version="1.0" encoding="UTF-8"?> Here are the distinct values: 1, 2, 3 The fn:insert-before FunctionAs you can guess from its name , the fn:insert-before function lets you insert one sequence into another. Here's how you use this function: fn:insert-before( $target as item*, $position as xs:integer, $inserts as item*) as item* This is the first of the sequence-editing functions that we'll cover. In this case, this function inserts the sequence $inserts into the $target sequence, starting at $position , and returns the results. Note that there is no "fn:insert-after" function. Here are a few examples: fn:insert-before((1, 2, 3), 1, 4) returns (4, 1, 2, 3) fn:insert-before((1, 2, 3), 2, 4) returns (1, 4, 2, 3) fn:insert-before((1, 2, 3), 3, 4) returns (1, 2, 4, 3) fn:insert-before((1, 2, 3), 4, 4) returns (1, 2, 3, 4) fn:insert-before((1, 2, 3), 4, (4, 5, 6)) returns (1, 2, 3, 4, 5, 6) fn:insert-before((1, 2, 3), 2, (4, 5, 6)) returns (1, 4, 5, 6, 2, 3) As you can see, this powerful function lets you put your own sequences together from other sequences. The fn:remove FunctionThis function simply removes an item from a sequence and returns the resulting sequence: fn:remove( $srcval as item*, $position as xs:integer) as item* The fn:remove function removes the item in $srcval at position $position and returns the resulting sequence. There's no provision here for removing more than one item. For example, we can convert the sequence (1, 2, 2, 3) to (1, 2, 3) using fn:remove , as you see in ch12_05.xsl (Listing 12.5). Listing 12.5 Using fn:remove ( ch12_05.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="/"> Here is the result: <xsl:value-of select="remove((1, 2, 2, 3), 3)" separator=", "/> </xsl:template> </xsl:stylesheet> And here's the result: <?xml version="1.0" encoding="UTF-8"?> Here is the result: 1, 2, 3 The fn:subsequence FunctionThe fn:subsequence function lets you extract a subsequence from a sequence. Here's how you use this function: fn:subsequence( $srcval as item*, $start as xs:double) as item* fn:subsequence( $srcval as item*, $start as xs:double, $length as xs:double) as item* This function is great when you want to carve a subsequence out of a sequence. Here are a few examples: fn:subsequence((1, 2, 3, 4), 2) returns (2, 3, 4) fn:subsequence((1, 2, 3, 4), 3) returns (3, 4) fn:subsequence((1, 2, 3, 4), 2, 2) returns (2, 3) The fn:unordered FunctionYou pass this function a sequenceor an expression that yields a sequenceand this function indicates that the resulting sequence may be returned in any order. Here's how you use this function: fn:unordered( $srcval as item*) as item* The fn:deep-equal FunctionThis function compares two sequences and returns a Boolean value: fn:deep-equal( $parameter1 as item*, $parameter2 as item*) as xs:boolean fn:deep-equal( $parameter1 as item*, $parameter2 as item*, $collationLiteral as string) as xs:boolean For this function to return a value of true , the two sequences must have the same values, which means that they have the same number of items and that items in corresponding positions in the two sequences must compare equal. Otherwise, the function returns false . Here are some examples: fn:deep-equal((1, 2, 3), (1, 2, 3, 4)) returns false. fn:deep-equal((1, 2, 3), (1, 2, 3)) returns true . The fn:count FunctionThe fn:count function works much the same way as the XPath 1.0 aggregate function count . In XPath 2.0, fn:count returns the number of items in a sequence. Here's how you use it: fn:count( $srcval as item*) as xs:integer For example, fn:count((1, 2, 3, 4)) returns 4, fn:count(()) returns 0, and fn:count((1, 2), (3, 4, 5)) returns 5. The fn:avg FunctionThis function averages the numeric values (as well as yearMonthDuration and dayTimeDuration values) you pass to it and returns the result: fn:avg( $srcval as xdt:anyAtomicType*) as xdt:anyAtomicType? This function just evaluates sum( $srcval ) div count( $srcval )) and returns the result. You can see an example in ch12_06.xsl (Listing 12.6), where we're averging the values 1, 2, 3, and 4. Listing 12.6 Using fn:avg ( ch12_06.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="/"> The average value is <xsl:value-of select="avg((1, 2, 3, 4))"/>. </xsl:template> </xsl:stylesheet> And here's the result: <?xml version="1.0" encoding="UTF-8"?> The average value is 2.5. The fn:max FunctionThe fn:max function returns the maximum value of a sequence of values: fn:max( $srcval as xdt:anyAtomicType*) as xdt:anyAtomicType? fn:max( $srcval as xdt:anyAtomicType*, $collation as string) as xdt:anyAtomicType? Note that you can also include a collation when calling this function. This function works as you'd expecthere are a few examples: fn:max((1, 2, 3)) returns 3. fn:max((1, 2, 1)) returns 2. fn:max((6, 5, 4, 3, 2, 1)) returns 6. The fn:min FunctionAs you can tell from this function's name, fn:min returns the minimum value from a sequence of values. Here are the signatures for this function: fn:min( $srcval as xdt:anyAtomicType*) as xdt:anyAtomicType? fn:min( $srcval as xdt:anyAtomicType*, $collation as string) as xdt:anyAtomicType? Here are some examples: fn:min((1, 2, 3)) returns 1. fn:min((7, 2, 1)) returns 1. fn:min((6, 5, 4, 3, 2)) returns 2. The fn:sum FunctionThis function returns a sum of the values that you pass it in a sequence: fn:sum($srcval as xdt:anyAtomicType*) as xdt:anyAtomicType? You can see an example in ch12_07.xsl (Listing 12.7), where we're using this function to add up the total masses in our planetary data document. Listing 12.7 Using fn:sum ( ch12_07.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="/"> The total mass is <xsl:value-of select="sum(//planet/mass)"/>. </xsl:template> </xsl:stylesheet> And here's the result: <?xml version="1.0" encoding="UTF-8"?> The total mass is 1.8703. The fn:id FunctionThis function lets you retrieve element nodes with specified ids; here's how you use it: fn:id( $srcval as xs:string*) as element* In this case, $srcval is of type xs:string and is treated as if it were of type xs:IDREFS , that is, as a space-separated sequence of tokens, each of which is interpreted as an xs:IDREF . The function returns a sequence of those elements that have an ID value equal to one or more of the IDREFs in the list of IDREFs (the ID values are set using attributes of type xs:ID ). The fn:idref FunctionThis function works in much the opposite way as the fn:id functionit returns all the nodes with IDREF values that reference one or more of the IDs you pass to this function. Here's how it works: fn:idref( $srcval as xs:string*) as node* In this case, $srcval is treated as if it were a space-separated sequence of tokens, each interpreted as an ID. The fn:doc FunctionThe fn:doc function is an interesting function that lets you read in entire documents. You just supply the URI of the document: fn:doc( $uri as xs:string?) as document? Note that $uri here must be an xs:string that obeys the restrictions for xs:anyURI. When you use this function, it will return a valid document node from the new document you're reading in, unless the URI cannot be resolved. Say that you wanted to work with an entirely new document in the middle of processing another documentfor example, you may want to fetch some crucial data from that new document that will aid in processing the current document. Being able to work with multiple documents in this way is powerful. Here's an example; in this case, we'll read in our planetary data document and extract data from it. In this case, that document will be in the same directory as we're already working in, so we can load in that document using the fn:doc function this way in Saxon: <xsl:template match="/"> That planet is <xsl:value-of select="doc('ch02_01.xml')..."/>. </xsl:template> Now we have a document node for the target document, and can apply XPath expressions to it as you see in ch12_08.xsl (Listing 12.8), where we're extracting the name of the first planet in the document, which is Mercury. Listing 12.8 Using fn:doc ( ch12_08.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="/"> That planet is <xsl:value-of select="doc('ch02_01.xml')//planet[1]/name"/>. </xsl:template> </xsl:stylesheet> And here's the result you get when you run this through Saxon: <?xml version="1.0" encoding="UTF-8"?> That planet is Mercury. It's often more useful to load a new document into its own variable and work with that variable, which will be accessible throughout an XSLT document. For example, here's how that might look in this case, where we're assigning the planetary data document to a variable named $document : <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="document" select="doc('ch02_01.xml')"/> . . . Now we're free to use that variable in our XPath 2.0 expressions, like this: <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="document" select="doc('ch02_01.xml')"/> <xsl:template match="/"> That planet is <xsl:value-of select="$document//planet[1]/name"/>. </xsl:template> </xsl:stylesheet> You can also use the fn:doc function to compare two documents, using the is operator. You can see a simple example of this in ch12_09.xsl (Listing 12.9), where we're just comparing a document to itself. Listing 12.9 Using fn:doc to Compare Documents ( ch12_09.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="if(doc('ch02_01.xml') is doc('ch02_01.xml')) then 'The documents are the same.' else 'The documents are not the same.'"/> </xsl:template> </xsl:stylesheet> Here's the resultnot surprisingly, when you compare a document to itself, the comparison reveals that the compared documents are the same: <?xml version="1.0" encoding="UTF-8"?> The documents are the same. The fn:collection FunctionThis function is designed to let you work with collections of nodes, and here's how you use it: fn:collection( $srcval as xs:string) as node* You pass it an xs:string value that is restricted to legal values for xs:anyURI and this function will return a document node from that URI, unless there's been an error. This function is not implemented in Saxon yet. That completes our look at the node and sequence functionsand that completes our book on XPath 1.0 and 2.0. We've come far in this book and covered a great deal, from the most basic up through many advanced topics. All that's left is to put all this technology to work for yourself! |