<?xml version="1.0"?>
<!--
$Id: str-util.xsl,v 1.19 2005/11/02 15:53:56 matthieu Exp $

This XSLT stylesheet offers functions to manipulate strings
-->
<?xml-stylesheet href="http://www.w3.org/StyleSheets/base.css" type="text/css"?>
<?xml-stylesheet href="http://www.w3.org/2002/02/style-xsl.css" type="text/css"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:str="http://www.w3.org/2001/10/str-util.xsl" version="1.0">

<div xmlns="http://www.w3.org/1999/xhtml">
           <h1>
    <a href="http://www.w3.org/">
      <img src="http://www.w3.org/Icons/w3c_home" alt="W3C" />
    </a>

    XSLT Templates to manipulate strings</h1>
    <h2>Status</h2>
    <p>The templates in this stylesheet are used in several other ones. Please don't modify it without letting me know and don't break the current exposed API.</p>
    <h2>Variables</h2>
    <dl>
    <dt>str:uc</dt>
    <dd>L'ensemble des lettres en majuscule (pratique pour conversion majuscule-minuscule)</dd>
    <dt>str:lc</dt>
    <dd>L'ensemble des lettres en minuscule (pratique pour conversion majuscule-minuscule)</dd>
    </dl>
    <h2>Templates</h2>

    <dl>
        <dt>str:keep-before</dt>
        <dd>Takes a <var>string</var> and a <var>delimiter</var> parameters and returns the part of the string before the first appearance of <var>delimiter</var> in <var>string</var>, the complete <var>string</var> if <var>delimiter</var> is not in <var>string</var>.</dd>
	<dt>str:ends-with</dt>
	<dd>Takes a <var>string</var> and a <var>string2</var> parameters and returns <code>yes</code> if <var>string</var> ends with <var>string2</var>, nothing otherwise (please use <code>normalize-space()</code> on the results to avoid bad surprises</dd>
    <dt>str:has-token</dt>
    <dd>Takes a <var>string</var>, a <var>token</var> and an optinal <var>delimiter</var> (default at " ") parameters and returns if <var>token</var> is a token of <var>string</var> delimited by <var>delimiter</var> the value <var>token</var>, nothing (that is, an unspecified number of spaces; please use <code>normalize-space()</code> on the results to avoid bad surprises) else.</dd>
<dt>str:keep-before-last</dt>
        <dd>Takes a <var>string</var> and a <var>delimiter</var> parameters and returns the part of the string before the last appearance of <var>delimiter</var> in <var>string</var>, the complete <var>string</var> if <var>delimiter</var> is not in <var>string</var>.</dd>
<dt>str:replace</dt>
        <dd>Takes a <var>string</var>, and replace every occurence of the <var>toBeReplaced</var> parameter by the <var>replaceBy</var> parameter.</dd>
<dt>str:stripElements</dt>
        <dd>Takes a <var>string</var> and return it without the tags between <code>&lt;</code> and <code>&gt;</code>.</dd>

    </dl>
<hr/>
<address>$Id: str-util.xsl,v 1.19 2005/11/02 15:53:56 matthieu Exp $<br/><a href="../../People/Dom/">Dominique Hazael-Massieux</a></address>
<hr/>
</div>

  <xsl:variable name="str:uc">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>

  <xsl:variable name="str:lc">abcdefghijklmnopqrstuvwxyz</xsl:variable>



  <xsl:template name="str:keep-before">
    <xsl:param name="string"/>
    <xsl:param name="delimiter"/>
    <xsl:choose>
      <xsl:when test="$string">
        <xsl:choose>
          <xsl:when test="contains($string,$delimiter)">
            <xsl:value-of
            select="normalize-space(substring-before($string,$delimiter))" />
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="normalize-space($string)" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="normalize-space($string)" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="str:ends-with">
    <xsl:param name="string"/>
    <xsl:param name="string2"/>
    <xsl:if test="contains($string,$string2)">
      <xsl:variable name="length" select="string-length($string)"/>
      <xsl:variable name="suffix_length" select="string-length($string2)"/>
      <xsl:if test="boolean(substring($string,number($length - 
$suffix_length + 1))=$string2)">
        <xsl:text>yes</xsl:text>
      </xsl:if>
    </xsl:if>
  </xsl:template>

  <xsl:template name="str:has-token">
    <xsl:param name="string"/>
    <xsl:param name="token"/>
    <xsl:param name="delimiter" select="' '"/>
    <xsl:if test="$string=$token or starts-with($string,concat($token,$delimiter)) or contains($string,concat($delimiter,$token,$delimiter)) or (contains($string,concat($delimiter,$token)) and substring($string,string-length($string) - string-length($token) - string-length($delimiter) + 1)=concat($delimiter,$token))"><xsl:value-of select="$token"/></xsl:if>
  </xsl:template>

  <xsl:template name="str:keep-before-last">
    <xsl:param name="string"/>
    <xsl:param name="delimiter"/>
    <xsl:choose>
      <!-- If the string is empty, we don't need to go further (@@@ really?)-->
      <xsl:when test="$string">
        <xsl:choose>
          <!-- Does the string contains the said delimiter? -->
          <xsl:when test="contains($string,$delimiter)">
            <xsl:choose>
              <!-- Does the part of the string after the delimiter still contains the delimiter? -->
              <xsl:when test="contains(substring-after($string,$delimiter),$delimiter)">
                <!-- if yes, we concatene the first part of the string with the result of the (recursive) call to this template on the second part of the string -->
                <xsl:value-of select="concat(substring-before($string,$delimiter),$delimiter)"/><xsl:call-template name="str:keep-before-last">
                <xsl:with-param name="string" select="substring-after($string,$delimiter)"/>
                <xsl:with-param name="delimiter" select="$delimiter"/>
              </xsl:call-template>
              </xsl:when>
              <xsl:otherwise>
                <!-- Otherwise, we have delimited what we want -->
                <xsl:value-of
            select="substring-before($string,$delimiter)" />
              </xsl:otherwise>
            </xsl:choose>
          </xsl:when>
          <xsl:otherwise>
            <!-- The delimiter is not in the string, end of story -->
            <xsl:value-of select="$string" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:otherwise>
        <!-- If the string has a null value, we just send it back as is -->
        <xsl:value-of select="$string" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="str:replace">
    <xsl:param name="string"/>
    <xsl:param name="toBeReplaced"/>
    <xsl:param name="replaceBy"/>
    <xsl:choose>
      <!-- If the string or the toBeReplaced parameter is empty, we don't need to go further -->
      <xsl:when test="$string and $toBeReplaced">
        <xsl:choose>
          <!-- Does the string contains the substring we want to replace? -->
          <xsl:when test="contains($string,$toBeReplaced)">
            <xsl:choose>
              <!-- Does the part of the string after the delimiter still contains the delimiter? -->
              <xsl:when test="contains(substring-after($string,$toBeReplaced),$toBeReplaced)">
                <!-- if yes, we concatene the first part of the string with the string replaceBy -->
                <!-- and the result of the (recursive) call to this template on the second part of the string -->
                <xsl:value-of select="concat(substring-before($string,$toBeReplaced),$replaceBy)"/>
                <xsl:call-template name="str:replace">
                  <xsl:with-param name="string" select="substring-after($string,$toBeReplaced)"/>
                  <xsl:with-param name="toBeReplaced" select="$toBeReplaced"/>
                  <xsl:with-param name="replaceBy" select="$replaceBy"/>
                </xsl:call-template>
              </xsl:when>
              <xsl:otherwise>
                <!-- Otherwise, we have delimited what we want -->
                <xsl:value-of select="concat(substring-before($string,$toBeReplaced),$replaceBy)"/>
                <xsl:value-of select="substring-after($string,$toBeReplaced)" />
              </xsl:otherwise>
            </xsl:choose>
          </xsl:when>
          <xsl:otherwise>
            <!-- The substring we want to replace is not in the string, end of story -->
            <xsl:value-of select="$string" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:otherwise>
        <!-- If the string has a null value, we just send it back as is -->
        <xsl:value-of select="$string" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

 <xsl:template name="str:stripElements">
   <xsl:param name="string"/>
   <xsl:variable name="before" select="substring-before($string,'&lt;')"/>
   <xsl:choose>
     <xsl:when test="$before or starts-with($string,'&lt;')">
       <xsl:value-of select="$before"/>
       <xsl:variable name="after"  select="substring-after($string,'&lt;')"/>
       <xsl:variable name="tag"  select="substring-before($after,'&gt;')"/>
       <xsl:choose>
	 <xsl:when test="$tag">
	   <xsl:call-template name="str:stripElements">
	     <xsl:with-param name="string" select="substring-after($after,'&gt;')"/>
	   </xsl:call-template>
	 </xsl:when>
	 <xsl:otherwise>
	   TAG is not closed properly.
	 </xsl:otherwise>
       </xsl:choose>
     </xsl:when>
     <xsl:otherwise>
       <xsl:value-of select="$string"/>
     </xsl:otherwise>
   </xsl:choose>
 </xsl:template>

</xsl:stylesheet>
