Recipe2.8.Converting Case


Recipe 2.8. Converting Case

Problem

You want to convert an uppercase string to lowercase or vice versa.

Solution

XSLT 1.0

Use the XSLT translate( ) function. This code, for example, converts from upper- to lowercase:

translate($input,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')

This example converts from lower- to uppercase:

translate($input, 'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')

XSLT 2.0

Use the XPath 2.0 functions upper-case() and lower-case( ) :

upper-case($input) lower-case($input)

Discussion

This recipe is, of course, trivial. However, I include it as an opportunity to discuss the XSLT 1.0 solution's shortcomings. Case conversion is trivial as long as your text is restricted to a single locale. In English, you rarely, if ever, need to deal with special characters containing accents or other complicated case conversions in which a single character must convert to two characters. The most common example is German, in which the lowercase ß (eszett) is converted to an uppercase SS. Many modern programming languages provide case-conversion functions that are sensitive to locale, but XSLT does not support this concept directly. This is unfortunate, considering that XSLT has other features supporting internationalization.

A slight improvement can be made by defining general XML entities for each type conversion, as shown in the following example:

<?xml version="1.0" encoding="UTF-8"?>    <!DOCTYPE stylesheet [      <!ENTITY UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ">      <!ENTITY LOWERCASE "abcdefghijklmnopqrstuvwxyz">      <!ENTITY UPPER_TO_LOWER " '&UPPERCASE;' , '&LOWERCASE;' ">      <!ENTITY LOWER_TO_UPPER " '&LOWERCASE;' , '&UPPERCASE;' "> ]> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">      <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>          <xsl:template match="/">      <xsl:variable name="test"           select=" 'The rain in Spain falls mainly on the plain' "/>      <output>           <lowercase>                <xsl:value-of                     select="translate($test,&UPPER_TO_LOWER;)"/>           </lowercase>           <uppercase>                <xsl:value-of                     select="translate($test,&LOWER_TO_UPPER;)"/>           </uppercase>      </output>      </xsl:template>     </xsl:stylesheet>

These entity definitions accomplish three things. First, they make it easier to port the stylesheet to another locale because only the definition of the entities UPPERCASE and LOWERCASE need be changed. Second, they compact the code by eliminating the need to list all letters of the alphabet twice. Third, they make the intent of the translate call obvious to someone inspecting the code. Some purists might object to the macro-izing away of translate()'s third parameter, but I like the way it makes the code read. If you prefer to err on the pure side, then use translate($test, &UPPERCASE;, &LOWERCASE;).

I have not seen entities used very often in other XSLT books; however, I believe the technique has merit. In fact, one benefit of XSLT being written in XML syntax is that you can exploit all features of XML, and entity definition is certainly a useful one. If you intend to use this technique and plan to write more than a few stylesheets, then consider placing common entity definitions in an external file and include them as shown in Example 2-6. You can also store these values in global variables in an external stylesheet and import them as needed. This alternative is preferred by many XSLT veterans.

Example 2-6. Standard.ent
<!ENTITY UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ">    <!ENTITY LOWERCASE "abcdefghijklmnopqrstuvwxyz"> <!ENTITY UPPER_TO_LOWER " '&UPPERCASE;' , '&LOWERCASE;' "> <!ENTITY LOWER_TO_UPPER " '&LOWERCASE;' , '&UPPERCASE;' "> <!-- others... -->

Then use a parameter entity defined in terms of the external standard.ent file, as shown in Example 2-7.

Example 2-7. A stylesheet using standard.ent
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE stylesheet [      <!ENTITY % standard SYSTEM "standard.ent">      %standard; ]> <xsl:stylesheet version="1.0"  <!-- ... --> </xsl:stylesheet>

Steve Ball's implementation of case conversion works in virtually all cases by including all the most common Unicode characters in the upper- and lowercase strings and taking special care to handle the German ß correctly.

XSLT 2.0

The new XPath 2.0 functions upper-case( ) and lower-case( ) resolve most of the issue with case conversion that can occur in non-English alphabets. The one exception is Unicode locale-sensitive conversions. It is best not to use these functions for the purpose of doing case insensitive comparison. Rather, use compare( ) with a collation that ignores case. Saxon 8.x user can find information about collations at http://www.saxonica.com/documentation/conformance/collation-uri.html and http://www.saxonica.com/documentation/extensions/instructions/collation.html.

See Also

Steve Ball's solution is available in the "Standard XSLT Library" at http://xsltsl.sourceforge.net/.




XSLT Cookbook
XSLT Cookbook: Solutions and Examples for XML and XSLT Developers, 2nd Edition
ISBN: 0596009747
EAN: 2147483647
Year: 2003
Pages: 208
Authors: Sal Mangano

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net