This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

replace-string() convenience function proposal



I would like a function such as replace-string() that would allow me to
replace one specified string with another specified string, within a
specified string.  For example, replace-string("Hello there", "Hello", "Hi")
would return "Hi there".  I use the following stylesheet (adapted from an
example in Kay's book) to do this for me now.

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template name="replace-string">
    <xsl:param name="text"/>
    <xsl:param name="replace"/>
    <xsl:param name="with"/>
    <xsl:choose>
      <xsl:when test="contains($text,$replace)">
        <xsl:value-of select="substring-before($text,$replace)"/>
        <xsl:value-of select="$with"/>
        <xsl:call-template name="replace-string">
          <xsl:with-param name="text"
select="substring-after($text,$replace)"/>
          <xsl:with-param name="replace" select="$replace"/>
          <xsl:with-param name="with" select="$with"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$text"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

Not only is the implementation lengthy and messy, but each time you call it,
you have to pass parameters all over the place.  Here's an example of where
I need to escape curly braces in attribute values in a generated stylesheet
(admittedly not the most frequent use-case, but a simple requirement
nevertheless):

  <!-- brace-escaping to guard against interpretation as AVTs in the
output -->
  <xsl:template match="@*" mode="rootRule">
    <xsl:variable name="leftBraceReplaced">
      <xsl:call-template name="replace-string"> <!-- imported template -->
        <xsl:with-param name="text" select="."/>
        <xsl:with-param name="replace" select="'{'"/>
        <xsl:with-param name="with" select="'{{'"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="bothBracesReplaced">
      <xsl:call-template name="replace-string">
        <xsl:with-param name="text" select="$leftBraceReplaced"/>
        <xsl:with-param name="replace" select="'}'"/>
        <xsl:with-param name="with" select="'}}'"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:attribute name="{name()}">
      <xsl:value-of select="$bothBracesReplaced"/>
    </xsl:attribute>
  </xsl:template>

Now, compare all of that code to the following code:

<xsl:attribute name="{name()}">
  <xsl:value-of select="replace-string(replace-string(., '{', '{{'), '}',
'}}')"/>
</xsl:attribute>

The translate() function is great for one-to-one character replacements, but
as soon as you want to replace a character with, say, two characters (as in
my example), you have to write a named template that recursively calls
itself, and pass all the parameters via <xsl:with-param/> each time you need
to call it, which, as you can see, can get quite ugly.

I don't care what this function is called; maybe just replace() would be
better.

Anyone want to second this motion (assuming it hasn't already been
proposed)?

Evan Lenz
elenz@xyzfind.com
http://www.xyzfind.com
XYZFind Corp. "Building Better Search"


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]