Attributes The Details on the xsl:sort Element

page 110 xsl:value-of select=newline xsl:for-each xsl:template xsl:stylesheet When we sort these elements using data-type=text , heres what we get: 10 127 23 We get this result because a text-based sort puts anything that starts with a 1 before anything that starts with a 2. If we change the xsl:sort element to be xsl:sort select=. data-type=number , we get these results: 10 27 123 If you use something else here data-type=floating-point , for example, what the XSLT processor does is anybodys guess. The XSLT specification allows for other values here, but its up to the XSLT processor to decide how or if it wants to process those values. Check your processors documentation to see if it does anything relevant or useful for values other than data-type=text or data-type=number . A final note: if youre using data-type=number , and any of the values arent numbers, those non-numeric values will sort before the numeric values. That means if youre using order=ascending , the non-numeric values appear first; if you use order=descending , the non-numeric values appear last. ?xml version=1.0? numberlist number127number number23number numberzzznumber number10number numberyyynumber numberlist Given this less-than-perfect data, here are the correctly sorted results: zzz yyy 10 23 127 Notice that the non-numeric values were not sorted; they simply appear in the output document in the order in which they were encountered. order You can order the sort as order=ascending or order=descending . The default is order=ascending . case-order This attribute can have two values. case-order=upper-first means that uppercase letters sort before lowercase letters, and case-order=lower-first means that lowercase letters sort first. The case-order attribute is used only when the data-type attribute is text . The default value depends on the value of the soon-to-be-discussed lang attribute. page 111 lang This attribute defines the language of the sort keys. The valid values for this attribute are the same as those for the xml:lang attribute defined in Section 2.12 of the XML 1.0 specification. The language codes are those commonly used in Java programming, UNIX locales, and other places ISO language and country namings are defined. For example, lang=en means English, lang=en-US means U.S. English, and lang=en-GB means U.K. English. Without the lang attribute its rarely used in practice, the XSLT processor determines the default language from the system environment. 6.1.2.3 Where can you use xsl:sort? The xsl:sort element can appear inside two elements: • xsl:apply-templates • xsl:for-each If you use an xsl:sort element inside xsl:for-each , the xsl:sort elements must appear first. If you tried something like this, youd get an exception from the XSLT processor: xsl:for-each select=addressbookaddress xsl:sort select=namelast-name xsl:value-of select=nametitle xsl:sort select=namefirst-name -- NOT LEGAL -- ...

6.1.3 Another Example

Weve pretty much covered the xsl:sort element at this point. To add another wrinkle to our example, well change the stylesheet so the xsl:sort element acts upon a subset of the addresses, then sorts that subset. Well sort only the addresses from states that start with the letter M . As youd expect, well do this magic with an XPath expression that limits the elements to be sorted: ?xml version=1.0? xsl:stylesheet version=1.0 xmlns:xsl=http:www.w3.org1999XSLTransform xsl:output method=text indent=no xsl:strip-space elements= xsl:variable name=newline xsl:text xsl:text xsl:variable xsl:template match= xsl:for-each select=addressbookaddress[starts-withstate, M] xsl:sort select=namelast-name xsl:sort select=namefirst-name xsl:if test=nametitle xsl:value-of select=nametitle xsl:text xsl:text xsl:if xsl:value-of select=namefirst-name xsl:text xsl:text xsl:value-of select=namelast-name xsl:value-of select=newline xsl:value-of select=street xsl:value-of select=newline xsl:value-of select=city xsl:text, xsl:text xsl:value-of select=state page 112 xsl:text xsl:text xsl:value-of select=zip xsl:value-of select=newline xsl:value-of select=newline xsl:for-each xsl:template xsl:stylesheet Here are the results, only those addresses from states beginning with the letter M , sorted by first name within last name: Ms. Natalie Attired 707 Breitling Way Winter Harbor, ME 00218 Harry Backstayge 283 First Avenue Skunk Haven, MA 02718 Mary Backstayge 283 First Avenue Skunk Haven, MA 02718 Ms. Amanda Reckonwith 930-A Chestnut Street Lynn, MA 02930 Notice that in the xsl:for-each element, we used a predicate in our XPath expression so that only addresses containing state elements whose contents begin with M are selected. This example starts us on the path to grouping nodes. We could do lots of other things here: • We could generate output that prints all the unique Zip Codes, along with the number of addresses that have those Zip Codes. • For each unique Zip Code or state, or last name, etc. we could sort on a field and list all addresses with that Zip Code. Well discuss these topics in the next section.

6.2 Grouping Nodes

When grouping nodes, we sort things to get them into a certain order, then we group all items that have the same value for the sort key or keys. Well use xsl:sort for this grouping, then use variables or functions like key or generate-id to finish the job.

6.2.1 Our First Attempt

For our first example, well take our list of addresses and group them. Well look for all unique values of the zip element and list the addresses that match each one. What well do is sort the list by Zip Code, then go through the list. If a given item doesnt match the previous Zip Code, well print out a heading; if it does match, well just print out the address. Heres our first attempt: ?xml version=1.0? xsl:stylesheet version=1.0 xmlns:xsl=http:www.w3.org1999XSLTransform xsl:output method=text indent=no xsl:variable name=newline xsl:text xsl:text xsl:variable xsl:template match= xsl:textAddresses sorted by Zip Codexsl:text xsl:value-of select=newline