Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Occasional XSLT for Experienced Software Developers : Page 5

Although using XSLT to process XML is increasingly common, most developers still use it only occasionally—and often treat it as just another procedural language. But that's not the best way to use XSLT. Learn how to simplify and improve your XSLT processing using event-driven and declarative techniques.


advertisement
Using Complex Keys in XSLT
Because the use attribute of the key definition is an XPath expression, it's possible to create quite elaborate indexes that rely upon complex XPath statements. As an example, generate-id() makes a unique key for every <book> node.

<xsl:key name="kbook" match="book" use="generate-id()"/>

The International Standard Book Number, or ISBN (sometimes pronounced "is-ben"), is a unique identifier for books, intended to be used commercially. The following declaration calculates the checksum of an ISBN number by returning true if the checksum passes the test and false otherwise.

You can find the check digit of an ISBN by first multiplying each digit of the ISBN by that digit's place in the number sequence, with the leftmost digit being multiplied by 1, the next digit by 2, and so on. Next, take the sum of these multiplications and calculate the sum modulo 11, with "10" represented by the character "X". As an example, for the ISBN 1-56592-235-2, the calculation would be (1*1 + 2*5 + 3*6 + 4*5 + 5*9 + 6*2 + 7*2 + 8*3 + 9*5) mod 11. The translate function deletes all the dash (-) characters from the @isbn attribute value. The following example uses the substring function to extract each character from the string returned by translate.

<xsl:key name="kbook" match="book" use="boolean( (substring(translate(@isbn, '-',''), 1,1) * 1 + substring(translate(@isbn, '-',''), 2,1) * 2 + substring(translate(@isbn, '-',''), 3,1) * 3 + substring(translate(@isbn, '-',''), 4,1) * 4 + substring(translate(@isbn, '-',''), 5,1) * 5 + substring(translate(@isbn, '-',''), 6,1) * 6 + substring(translate(@isbn, '-',''), 7,1) * 7 + substring(translate(@isbn, '-',''), 8,1) * 8 + substring(translate(@isbn, '-',''), 9,1) * 9) mod 11 - substring(translate(@isbn, '-',''),10,1)) or (boolean( (substring(translate(@isbn, '-',''), 1,1) * 1 + substring(translate(@isbn, '-',''), 2,1) * 2 + substring(translate(@isbn, '-',''), 3,1) * 3 + substring(translate(@isbn, '-',''), 4,1) * 4 + substring(translate(@isbn, '-',''), 5,1) * 5 + substring(translate(@isbn, '-',''), 6,1) * 6 + substring(translate(@isbn, '-',''), 7,1) * 7 + substring(translate(@isbn, '-',''), 8,1) * 8 + substring(translate(@isbn, '-',''), 9,1) * 9) mod 11 = 10) and (substring(translate(@isbn, '-',''),10,1)) = 'X')"/>

Branching vs. Modes in XSLT
XSLT's branching powers are weak compared to the branching statements of conventional languages. Instead, you can use the powerful mechanism of modes—often unexplored by occasional XSLT programmers.

Suppose you have to print all the titles and their respective ISBN codes, checking for the ISBN code validity at the same time. You could represent the desired result as follows:



<?xml version="1.0" encoding="utf-8"?> <table> <th>ISBN number check failed</th> <tr> <td class="color:red;">1-56592-235-1</td> </tr> </table><table> <th>ISBN number check passed</th> <tr> <td>1-56592-235-2</td> </tr> <tr> <td>0-471-40399-7</td> </tr> </table>

Without knowing how to use keys and modes, you might implement the solution with the following stylesheet logic:

<xsl:choose> <xsl:when test=""> </xsl:when> <xsl:otherwise> </xsl:otherwise> </xsl:choose>

This example would construct the table by iterating on the ISBN nodes and choosing whether to output class="color:red;" on each pass. This would be easy if you weren't obliged to group the result and output all the failed ISBN codes first. For the purpose of grouping, the use of keys and modes leads to much simpler code, the alternatives being extension functions or chaining of two different XSLT stylesheets.

<?xml version="1.0" ?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output indent="yes" encoding="utf-8"/> <xsl:key name="kbook" match="book" use="boolean( (substring(translate(@isbn, '-',''), 1,1) * 1 + substring(translate(@isbn, '-',''), 2,1) * 2 + substring(translate(@isbn, '-',''), 3,1) * 3 + substring(translate(@isbn, '-',''), 4,1) * 4 + substring(translate(@isbn, '-',''), 5,1) * 5 + substring(translate(@isbn, '-',''), 6,1) * 6 + substring(translate(@isbn, '-',''), 7,1) * 7 + substring(translate(@isbn, '-',''), 8,1) * 8 + substring(translate(@isbn, '-',''), 9,1) * 9) mod 11 - substring(translate(@isbn, '-',''),10,1)) or (boolean( (substring(translate(@isbn, '-',''), 1,1) * 1 + substring(translate(@isbn, '-',''), 2,1) * 2 + substring(translate(@isbn, '-',''), 3,1) * 3 + substring(translate(@isbn, '-',''), 4,1) * 4 + substring(translate(@isbn, '-',''), 5,1) * 5 + substring(translate(@isbn, '-',''), 6,1) * 6 + substring(translate(@isbn, '-',''), 7,1) * 7 + substring(translate(@isbn, '-',''), 8,1) * 8 + substring(translate(@isbn, '-',''), 9,1) * 9) mod 11 = 10) and (substring(translate(@isbn, '-',''),10,1)) = 'X')"/> <xsl:template match="/"> <table> <th>ISBN number check failed</th> <xsl:apply-templates select="key('kbook',true())" mode="failed"/> </table> <table> <th>ISBN number check passed</th> <xsl:apply-templates select="key('kbook',false())" mode="passed"/> </table> </xsl:template> <xsl:template match="book" mode="failed"> <tr> <td class="color:red;"> <xsl:value-of select="@isbn"/> </td> </tr> </xsl:template> <xsl:template match="book" mode="passed"> <tr> <td> <xsl:value-of select="@isbn"/> </td> </tr> </xsl:template> <xsl:template match="text()"/> </xsl:stylesheet>

This version processes both types of book nodes—those that did not pass checksum verification for their ISBN codes, and those that did—using separate templates for the failed and passed modes. The stylesheet outputs ISBN values in red for books with ISBN codes that fail the checksum test.



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap