Our First Example Sorting Data with xsl:sort

page 106 address name first-nameHarryfirst-name last-nameBackstaygelast-name name street283 First Avenuestreet citySkunk Havencity stateMAstate zip02718zip address address name first-nameMaryfirst-name last-nameMcGoonlast-name name street103 Bryant Streetstreet cityBoylstoncity stateVAstate zip27318zip address address name titleMs.title first-nameAmandafirst-name last-nameReckonwithlast-name name street930-A Chestnut Streetstreet cityLynncity stateMAstate zip02930zip address addressbook Wed like to generate a list of these addresses, sorted by last-name . Well use the magical xsl:sort element to do the work. Our stylesheet looks like this: ?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 xsl:sort select=namelast-name xsl:value-of select=nametitle xsl:text xsl:text 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 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 page 107 The heart of our stylesheet are the xsl:for-each and xsl:sort elements. The xsl:for- each element selects the items with which well work, and the xsl:sort element rearranges them before we write them out. Notice that were generating a text file xsl:output method=text . You could generate an HTML file or something more complicated if you want. To invoke the stylesheet engine, we run this command: java org.apache.xalan.xslt.Process -in names.xml -xsl namesorter1.xsl -out names.text Here are the results we get from our first attempt at sorting: Ms. Natalie Attired 707 Breitling Way Winter Harbor, ME 00218 Mary Backstayge 283 First Avenue Skunk Haven, MA 02718 Harry Backstayge 283 First Avenue Skunk Haven, MA 02718 Mr. Chester Hasbrouck Frisby 1234 Main Street Sheboygan, WI 48392 Mary McGoon 103 Bryant Street Boylston, VA 27318 Ms. Amanda Reckonwith 930-A Chestnut Street Lynn, MA 02930 As you can see from the output, the addresses in our original document were sorted by last name. All we had to do was add xsl:sort to our stylesheet, and all the elements were magically reordered. If you arent convinced that XSLT can increase your programmer productivity, try writing the Java code and DOM method calls to do the same thing. We can do a couple of things to improve our original stylesheet, however. For one thing, theres an annoying blank space at the start of every name that doesnt have a title element. A more significant improvement is that wed like to sort addresses by first-name within last-name . In our last example, Mary Backstayge should appear after Harry Backstayge. Heres how we can modify our stylesheet to use more than one sort key: xsl:template match= xsl:for-each select=addressbookaddress xsl:sort select=namelast-name xsl:sort select=namefirst-name ... Weve simply added a second xsl:sort element to our stylesheet. This element does what we want; it sorts the address elements by first-name within last-name . To be thoroughly obsessive about our output, we can use an xsl:if element to get rid of that annoying blank space in front of names with no title element: xsl:if test=nametitle xsl:value-of select=nametitle xsl:text xsl:text xsl:if page 108 Now our output is perfect: 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 Mr. Chester Hasbrouck Frisby 1234 Main Street Sheboygan, WI 48392 Mary McGoon 103 Bryant Street Boylston, VA 27318 Ms. Amanda Reckonwith 930-A Chestnut Street Lynn, MA 02930

6.1.2 The Details on the xsl:sort Element

Now that weve seen a couple of examples of how xsl:sort works, well go over its syntax, its attributes, and where you can use it. 6.1.2.1 Whats the deal with that syntax? Im so glad you asked that question. One thing the XSLT working group could have done is something like this: xsl:for-each select=addressbookaddress sort-key-1=namelast-name sort-key-2=namefirst-name The problem with this approach is that no matter how many sort-key-x attributes you define, out of sheer perverseness, someone will cry out that they really need the sort-key-8293 attribute. To avoid this messy problem, the XSLT designers decided to let you specify the sort keys by using a number of xsl:sort elements. The first is the primary sort key, the second is the secondary sort key, the 8293rd one is the eight-thousand-two-hundred-and- ninety-third sort key, etc. Well, thats why the syntax looks the way it does, but how does it actually work? When I first saw this syntax: xsl:for-each select=addressbookaddress xsl:sort select=namelast-name xsl:sort select=namefirst-name xsl:apply-templates select=. xsl:for-each I thought it meant that all the nodes were sorted during each iteration through the xsl:for- each element. That seemed incredibly inefficient; if youve sorted all the nodes, why resort them each time through the xsl:for-each element? Actually, the XSLT processor handles all xsl:sort elements before it does anything, then it processes the xsl:for-each element as if the xsl:sort elements werent there. page 109 Its less efficient, but if it makes you feel better about the syntax, you could write the stylesheet like this: xsl:template match= xsl:for-each select=addressbookaddress xsl:sort select=namelast-name xsl:sort select=namefirst-name xsl:for-each select=. -- This is slower, but it works -- xsl:apply-templates select=. xsl:for-each xsl:for-each xsl:template Dont actually do this. Im only trying to make a point. This stylesheet generates the same results as our earlier stylesheet.

6.1.2.2 Attributes

The xsl:sort element has several attributes, all of which are discussed here. select The select attribute defines the characteristic well use for sorting. Its contents are an XPath expression, so you can select elements, text, attributes, comments, ancestors, etc. As always, the XPath expression defined in select is evaluated in terms of the current context. data-type The data-type attribute can have three values: • data-type=text • data-type=number • A data-type=QName that identifies a particular datatype. The stated goal of the XSLT working group is that the datatypes defined in the XML Schema specification will eventually be supported here. The XSLT specification defines the behavior for data-type=text and data- type=number . Consider this XML document: ?xml version=1.0? numberlist number127number number23number number10number numberlist Well sort these values using the default value data-type=text : ?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=numberlistnumber xsl:sort select=. xsl:value-of select=.