Re: [xsl] search and replace

Subject: Re: [xsl] search and replace
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Thu, 29 Apr 2004 14:57:22 +0100
Hi Norma,

> I found this template on the list but am not sure how to implement
> it. I'm trying to replace ??degrees?? with &#xb0; in all xml tags.
> Is it possible and can someone explain how this template
> would/should work?
>
> I've tried a few variations and I keep getting an error that
> call-template not allowed in stylesheet message.

I think that the error's arising because you've got the
<xsl:call-template> element at the top level of your stylesheet. It
can only appear within a template. Since you want to make the
replacement inside all the elements in your document, I suggest having
a template that matches all text nodes, and putting the template call
within that:

<xsl:template match="text()">
  <xsl:call-template name="_replace_string">
    <xsl:with-param name="string" select="." />
    <xsl:with-param name="find" select="'??degrees??'" />
    <xsl:with-param name="replace" select="'&#xB0;'" />
  </xsl:call-template>
</xsl:template>

Make sure that the templates that you have to process the elements
contain a <xsl:apply-templates> instruction to process their text node
children rather than a <xsl:value-of> instruction, otherwise this
template won't get used.

The <xsl:call-template> in the above template calls the template with
$string set to the value of the text node, $find set to the string
'??degrees??' and $replace set to the string '&#xB0;' (the degree
sign, I assume).

The _replace_string template is a recursive template that replaces all
the instances of $find in $string with $replace. It first tests to see
whether $string contains $find or not; if not, then all it has to do
is output $string itself.

> <xsl:choose>
>   <xsl:when test="contains($string,$find)">
[snip]
>   </xsl:when>
>   <xsl:otherwise>
>     <xsl:value-of select="$string"/>
>   </xsl:otherwise>
> </xsl:choose>

If $string *does* contain $find, then the template identifies the
substring before $find with substring-before($string, $find) and
outputs that, concatenated with the $replace string.

> <xsl:value-of
>   select="concat(substring-before($string,$find),$replace)"/>

Then the template moves on to the next part of the string, the
substring after the first instance of $find in $string. It calls the
template again, but with a different value for $string (this is the
recursive call):

> <xsl:call-template name="_replace_string">
>   <xsl:with-param name="string"
>     select="substring-after($string,$find)"/>
>   <xsl:with-param name="find" select="$find"/>
>   <xsl:with-param name="replace" select="$replace"/>
> </xsl:call-template>

I hope this explains things; come back to us with any questions.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/

Current Thread