Search

Both my Google and XSLT-fu is failing me today. Anyone have a utility that will find and replace a series of words? It needs to match whole words only, and replace a set of words that's populated from an XML field. Something akin to:

<patterns>
  <pattern>
    <old>hullo</old>
    <new>hello</new>
  </pattern>
  <pattern>
    <old>hallo</old>
    <new>hello</new>
  </pattern>
</pattern>

I think it depends a bit on if you are dealing with a basic string or something that has tags/nodes thorugh it (<p> etc).

But if it's a basic string you can use string functions to do a basic find and replace:

<xsl:template name="find-replace">
<xsl:param name="old"/>
<xsl:param name="new"/>
<xsl:param name="textblock"/>

<xsl:if test="contains($textblock,$old)">
    <xsl:value-of select="replace($textblock,$old,$new)"/>
    </xsl:if>
</xsl:template>

<xsl:call-template name="find-replace">
<xsl:with-param name="old" select="patterns/pattern/old"/>
<xsl:with-param name="new" select="patterns/pattern/new"/>
<xsl:with-param name="textblock" select="path/to/string"/>
</xsl:call-template>

That obviously isn't the whole answer (only works for a single change) but if you need to make multiple changes to the same string you could wrap the output of the utility in <xsl:param name="result"> tags and then use recursion to keep calling the template using $result as the $textblock until you've got through all the words on your list.

Or something like that.... my brain isn't working too well at the end of the day!

Hopefully that was some help..

There's a string replace utility which would be useful too. You'll need a named template that calls itself recursively, passing back the transformed string each time. To match whole words only you could append a space to the beginning and end of your original string, then also append spaces to the search word. Do you need to handle plurals, punctuation and case sensitivity?

Not so worried about case-sensitivity or punctuation, I do need to worry about new lines though. Though I could account for both those with multiple entries. It doesn't need to be all that smart. What's the best way to step through a set of source nodes recursively and pass an input parameter between them?

I would look at the str:tokenize function to split by space, then store this in a temp tree using node-set(). Then use for-each to output each node. In your for-each, check each word in the node and match it against your word replace index. If matched, output the replacement word. If not, output as-is.

That'll remove new lines and additional whitespace from the output though, right?

Thanks for the help, folks. Ending up doing this: https://gist.github.com/943886

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details