The XPath String Functions

The XPath String Functions

The following XPath string functions are available in XSLT:

  • concat(string string1 , string string2 , ...) . This function returns all strings you pass to it concatenated together.

  • contains(string string1 , string string2 ) . This function checks for the existence of the second string within the first stringreturns true if found.

  • normalize-space(string string1 ) . This function returns string1 (or context node if no string1) after leading and trailing whitespace is stripped and multiple consecutive whitespace is replaced with a single space.

  • starts-with (string string1 , string string2 ) . This function returns true if the first string starts with the second string.

  • string-length (string string1 ) . This function returns the number of characters in string1 .

  • substring(string string1 , number offset , number length ) . This function returns length characters from the string, starting at offset.

  • substring-after(string string1 , string string2 ) . This function returns the part of string1 starting after the first occurrence of string2 .

  • substring-before (string string1 , string string2 ) . This function returns the part of string1 up to the first occurrence of string2 .

  • translate(string string1 , string string2 , string string3 ) . This function returns string1 with all occurrences of the characters in string2 replaced by the matching characters in string3 .

go through each of these string functions in the sections that follow.

concat()

The concat function concatenates as many strings together as you pass to it, returning the concatenated string:

 concat(string  string1  , string  string2  , ...) 

For an example, look at the version of planets.xsl developed earlier in this book that displayed element values and the values of the UNITS attributes and used templates in this way:

 <xsl:template match="MASS">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:value-of select="@UNITS"/>      </xsl:template> 

This displays the string value, the context node, a space, and the string value of the UNITS attribute. However, you could make this a lot shorter with the concat function:

Listing 8.8 Using the concat Function
 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">      <xsl:template match="/PLANETS">          <HTML>          .          .          .          </HTML>      </xsl:template>      <xsl:template match="PLANET">         <TR>            <TD><xsl:value-of select="NAME"/></TD>            <TD><xsl:apply-templates select="MASS"/></TD>            <TD><xsl:apply-templates select="RADIUS"/></TD>            <TD><xsl:apply-templates select="DAY"/></TD>         </TR>     </xsl:template>      <xsl:template match="MASS">          <xsl:value-of select="concat(., ' ', @UNITS)"/>      </xsl:template>      <xsl:template match="RADIUS">          <xsl:value-of select="concat(., ' ', @UNITS)"/>      </xsl:template>      <xsl:template match="DAY">          <xsl:value-of select="concat(., ' ', @UNITS)"/>      </xsl:template>  </xsl:stylesheet> 

contains()

The contains function checks to see whether one string is contained inside another, and returns a value of true if so, false otherwise . Heres how you use this function:

 boolean contains(container-string, contained-string) 

The following example is from Chapter 7; in this case, I want to search all attributes for the word miles, and if found, add the text You should switch to kilometers. in the result document:

 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">      <xsl:template match="/PLANETS">          <HTML>          .          .          .          </HTML>      </xsl:template>      <xsl:template match="PLANET">         <TR>            <TD><xsl:value-of select="NAME"/></TD>            <TD><xsl:apply-templates select="MASS"/></TD>            <TD><xsl:apply-templates select="RADIUS"/></TD>            <TD><xsl:apply-templates select="DAY"/></TD>            <TD><xsl:apply-templates select="DISTANCE"/></TD>         </TR>     </xsl:template>      <xsl:template match="MASS">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:value-of select="@UNITS"/>      </xsl:template>          .          .          .      <xsl:template match="DISTANCE">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:value-of select="@UNITS"/>      </xsl:template>      <xsl:template match="//*[contains(@UNITS, 'miles')]">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:text>You should switch to kilometers.</xsl:text>      </xsl:template>  </xsl:stylesheet> 

Heres the result document:

 <HTML>      <HEAD>          <TITLE>              The Planets Table          </TITLE>      </HEAD>      <BODY>          <H1>              The Planets Table          </H1>          <TABLE BORDER="2">              <TR>                  <TD>Name</TD>                  <TD>Mass</TD>                  <TD>Radius</TD>                  <TD>Day</TD>                  <TD>Distance</TD>              </TR>              <TR>                  <TD>Mercury</TD>                  <TD>.0553 (Earth = 1)</TD>                  <TD>1516 You should switch to kilometers.</TD>                  <TD>58.65 days</TD>                  <TD>43.4 You should switch to kilometers.</TD>              </TR>              <TR>                  <TD>Venus</TD>                  <TD>.815 (Earth = 1)</TD>                  <TD>3716 You should switch to kilometers.</TD>                  <TD>116.75 days</TD>                  <TD>66.8 You should switch to kilometers.</TD>              </TR>              <TR>                  <TD>Earth</TD>                  <TD>1 (Earth = 1)</TD>                  <TD>2107 You should switch to kilometers.</TD>                  <TD>1 days</TD>                  <TD>128.4 You should switch to kilometers.</TD>              </TR>          </TABLE>      </BODY>  </HTML> 

normalize-space()

The normalize-space function removes leading and trailing whitespace and condenses all internal adjacent whitespace into a single space, returning the resulting string. Heres how you use this function:

 string normalize-space(string?) 

In the following example, I add extra whitespace to the UNITS element in Mercurys <MASS> element:

 <?xml version="1.0"?>  <?xml-stylesheet type="text/xml" href="planets.xsl"?>  <PLANETS>      <PLANET>          <NAME>Mercury</NAME>          <MASS UNITS=" (Earth   =    1) ">.0553</MASS>          <DAY UNITS="days">58.65</DAY>          <RADIUS UNITS="miles">1516</RADIUS>          <DENSITY UNITS="(Earth = 1)">.983</DENSITY>          <DISTANCE UNITS="million miles">43.4</DISTANCE><!--At perihelion-->      </PLANET>          .          .          . 

can remove the extra whitespace in the stylesheet with normalize-space :

 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">      <xsl:template match="/PLANETS">          <HTML>          .          .          .          </HTML>      </xsl:template>      <xsl:template match="PLANET">         <TR>            <TD><xsl:value-of select="NAME"/></TD>            <TD><xsl:apply-templates select="MASS"/></TD>            <TD><xsl:apply-templates select="RADIUS"/></TD>            <TD><xsl:apply-templates select="DAY"/></TD>         </TR>     </xsl:template>      <xsl:template match="MASS">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:value-of select="normalize-space(@UNITS)"/>      </xsl:template>          .          .          . 

And heres the resultnote that the extra whitespace has been removed:

 <HTML>      <HEAD>          <TITLE>              The Planets Table          </TITLE>      </HEAD>      <BODY>          <H1>              The Planets Table          </H1>          <TABLE BORDER="2">              <TR>                  <TD>Name</TD>                  <TD>Mass</TD>                  <TD>Radius</TD>                  <TD>Day</TD>              </TR>              <TR>                  <TD>Mercury</TD>                  <TD>.0553 (Earth = 1)</TD>                  <TD>1516 miles</TD>                  <TD>58.65 days</TD>              </TR>          .          .          . 

starts-with()

As you can guess from its name, you use the starts-with function to test whether one string starts with another.

 boolean starts-with(string-to-examine, possible-start-string) 

This example from Chapter 4 used starts-with to match text nodes whose text starts with E in order to match the Earth, and added the text (the World) to the description of Earth, making it Earth (the World):

 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">      <xsl:template match="/PLANETS">          <HTML>              <HEAD>          .          .          .              </BODY>          </HTML>      </xsl:template>      <xsl:template match="PLANET">         <TR>            <TD><xsl:apply-templates select="NAME"/></TD>            <TD><xsl:apply-templates select="MASS"/></TD>            <TD><xsl:apply-templates select="RADIUS"/></TD>            <TD><xsl:apply-templates select="DAY"/></TD>         </TR>     </xsl:template>      <xsl:template match="text()[starts-with(., 'E')]">          <xsl:text>(the World)</xsl:text>      </xsl:template>      <xsl:template match="NAME">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:value-of select="@UNITS"/>          <xsl:apply-templates/>      </xsl:template>          .          .          .      <xsl:template match="DAY">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:value-of select="@UNITS"/>      </xsl:template>  </xsl:stylesheet> 

And heres the resultnote that the caption for Earth has become Earth (the World):

 <HTML>      <HEAD>          <TITLE>              The Planets Table          </TITLE>      </HEAD>      <BODY>          <H1>              The Planets Table          </H1>          <TABLE BORDER="2">              <TR>                  <TD>Name</TD>                  <TD>Mass</TD>                  <TD>Radius</TD>                  <TD>Day</TD>              </TR>              .              .              .              <TR>                  <TD>Earth (the World)</TD>                  <TD>1 (Earth = 1)</TD>                  <TD>2107 miles</TD>                  <TD>1 days</TD>              </TR>          </TABLE>      </BODY>  </HTML> 

string()

The string function just converts the item you pass it to a string. Heres how you use this function:

 string string(object?) 

Usually, this function is not needed because these types of conversions are made automatically. In fact, I can think of only a few limited examples where you really need to use the string function. For one, imagine that for some reason you put three <NAME> elements into each <PLANET> element in planets.xml, and that you wanted to use only the first <NAME> element as the real name of the planet:

 <?xml version="1.0"?>  <?xml-stylesheet type="text/xml" href="planets.xsl"?>  <PLANETS>      <PLANET>          <NAME>Mercury</NAME>          <NAME>Venus</NAME>          <NAME>Earth</NAME>          <MASS UNITS="(Earth = 1)">.0553</MASS>          <DAY UNITS="days">58.65</DAY>          <RADIUS UNITS="miles">1516</RADIUS>          <DENSITY UNITS="(Earth = 1)">.983</DENSITY>          <DISTANCE UNITS="million miles">43.4</DISTANCE><!--At perihelion-->      </PLANET>      <PLANET>          <NAME>Venus</NAME>          <NAME>Earth</NAME>          <NAME>Mercury</NAME>          <NAME>Planet of Love.</NAME>          <MASS UNITS="(Earth = 1)">.815</MASS>          <DAY UNITS="days">116.75</DAY>          <RADIUS UNITS="miles">3716</RADIUS>          <DENSITY UNITS="(Earth = 1)">.943</DENSITY>          <DISTANCE UNITS="million miles">66.8</DISTANCE><!--At perihelion-->      </PLANET>      <PLANET>          <NAME>Earth</NAME>          <NAME>Mercury</NAME>          <NAME>Venus</NAME>          <NAME>The planet you're standing on.</NAME>          <MASS UNITS="(Earth = 1)">1</MASS>          <DAY UNITS="days">1</DAY>          <RADIUS UNITS="miles">2107</RADIUS>          <DENSITY UNITS="(Earth = 1)">1</DENSITY>          <DISTANCE UNITS="million miles">128.4</DISTANCE><!--At perihelion-->      </PLANET>  </PLANETS> 

Now imagine that you want to match a specific planet, such as Venus. This test doesnt work, because NAME returns a node set of all the context nodes <NAME> children, and because every planet has a <NAME> element with the name Venus in it, this test is always true:

 <xsl:template match="PLANET">      <xsl:if test="NAME='Venus'">         <TR>            <TD><xsl:value-of select="NAME"/></TD>            <TD><xsl:apply-templates select="MASS"/></TD>            <TD><xsl:apply-templates select="RADIUS"/></TD>            <TD><xsl:apply-templates select="DAY"/></TD>         </TR>      </xsl:if>     </xsl:template> 

If you want to test just the first <NAME> element in each <PLANET> element, you can use the string function in the following way, because it returns a string, not a node set:

 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">      <xsl:template match="/PLANETS">          <HTML>          .          .          .          </HTML>      </xsl:template>      <xsl:template match="PLANET">      <xsl:if test="string(NAME)='Venus'">         <TR>            <TD><xsl:value-of select="NAME"/></TD>            <TD><xsl:apply-templates select="MASS"/></TD>            <TD><xsl:apply-templates select="RADIUS"/></TD>            <TD><xsl:apply-templates select="DAY"/></TD>         </TR>      </xsl:if>     </xsl:template>      <xsl:template match="MASS">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:value-of select="@UNITS"/>      </xsl:template>          .          .          .      <xsl:template match="DAY">          <xsl:value-of select="."/>          <xsl:text> </xsl:text>          <xsl:value-of select="@UNITS"/>      </xsl:template>  </xsl:stylesheet> 

Of course, its easier to use NAME[1] if you want to just match the first <NAME> child of the context node.

string-length()

As you can guess, the string-length function returns the length of a string you pass to it. Heres how you use this function:

 number string-length(string?) 

In the following example, I use string-length to find the length of each planets name:

 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">      <xsl:template match="/PLANETS">          <HTML>              <HEAD>                  <TITLE>                      Length of Planet Names                  </TITLE>              </HEAD>              <BODY>                  <H1>                      Length of Planet Names                  </H1>                      <xsl:apply-templates/>              </BODY>          </HTML>      </xsl:template>      <xsl:template match="PLANET">            <xsl:value-of select="NAME"/> is <xsl:value-of select="string-length(NAME)"/> graphics/ccc.gif characters long.            <BR/>     </xsl:template>      <xsl:template match="*">      </xsl:template>  </xsl:stylesheet> 

And heres the result:

 <HTML>      <HEAD>          <TITLE>              Length of Planet Names          </TITLE>      </HEAD>      <BODY>          <H1>              Length of Planet Names          </H1>          Mercury is 7 characters long.          <BR>          Venus is 5 characters long.          <BR>          Earth is 5 characters long.          <BR>      </BODY>  </HTML> 

You can see this result document in Figure 8.2.

Figure 8.2. Checking the length of strings in XSLT.
graphics/08fig02.gif

substring()

The substring function returns a substring of a string. Heres how you use this function:

 string substring(source-string, start-position, number-of-characters?) 

You pass this function a source-string , a start-position , and, optionally , a number-of-characters . This function returns the substring of the source string starting at the starting position and continuing for the number of characters youve specified, or to the end of the string if you havent specified a number of characters to return.

The substring function is one of a trio of substring functions: substring-before , which returns the string before a matched substring, substring itself, which returns substrings that you specify, and substring-after , which returns the substring after a match. The following example uses all three in this case, Ill chop the name of the planet Mercury up into three substringsMer, c, and uryand then concatenate them again. Heres how that works using these three functionssee the following two topics for more on substring-before and substring_after :

Listing 8.9 Using substring-before, substring, and substring-after
 <?xml version="1.0"?>  <xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">      <xsl:template match="/PLANETS">          <HTML>              <HEAD>                  <TITLE>                      Planetary Information                  </TITLE>              </HEAD>              <BODY>                  <H1>                      Planetary Information                  </H1>                      <xsl:apply-templates/>              </BODY>          </HTML>      </xsl:template>      <xsl:template match="PLANET">          <xsl:if test="NAME='Mercury'">            The first planet is            <xsl:value-of                select="concat(substring-before(NAME, 'c'),                substring(NAME, 4, 1), substring-after(NAME, 'c'))"/>.            <BR/>          </xsl:if>     </xsl:template>      <xsl:template match="*">      </xsl:template>  </xsl:stylesheet> 

And heres the result document created by this transformation:

 <HTML>      <HEAD>          <TITLE>              Planetary Information          </TITLE>      </HEAD>      <BODY>          <H1>              Planetary Information          </H1>          The first planet is Mercury.          <BR>      </BODY>  </HTML> 

substring-after()

The substring-after function returns the substring following a matched string. You supply this function with a string, and a string to match inside the string, and it returns the substring following the match if there was a match, and an empty string otherwise. Heres how you use this function:

 string substring-after(string, string-to-match) 

See the substring() topic for an example that uses the substring-before , substring , and substring-after functions.

substring-before()

You supply substring-before with a string, and a string to match inside the string, and it returns the substring preceding the match if there was a match; otherwise, it returns an empty string. Heres how you use substring-before :

 string substring-before(string, string-to-match) 

See the substring() topic for an example that uses the substring-before , substring , and substring-after functions.

translate()

You use the translate function to translate or replace specific characters. (This function is much like the tr operator in Perl, if youre familiar with operators.) You supply two strings: one is a list of characters to match, and the other is a list of characters with which to replace the matched characters. Heres how you use this function:

 string translate(string, from-characters, to-characters) 

For example, if the third character in from-characters is found in string , the third character in to-characters is substituted for it in the result string.

In the following example, this use of translate

 translate("steve-starpowder.com", "-", "@") 

returns the result string steve@starpowder.com.

Now in this example, Im just converting a string to lower case:

 translate("XSLT", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz") 


Inside XSLT
Inside Xslt
ISBN: B0031W8M4K
EAN: N/A
Year: 2005
Pages: 196

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