Replace String

H

Hvid Hat

Hi

I want to highlight (make it bold) a word in some text I'm getting in XML
format. My plan was to replace the word with a bold (or span) tag with the
word within the tag. I've found the code below and it works fine as long
as I'm not adding tags around the to parameter. Can anyone explain to me
why it doesn't work with tags? And it needs to be XSLT 1.0.

This works: X<xsl:value-of select="'little steak'"/>X
This doesn't work: <b><xsl:value-of select="'little steak'"/></b>

And the code:

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

<!-- reusable replace-string function -->
<xsl:template name="replace-string">
<xsl:param name="text"/>
<xsl:param name="from"/>
<xsl:param name="to"/>

<xsl:choose>
<xsl:when test="contains($text, $from)">

<xsl:variable name="before" select="substring-before($text, $from)"/>
<xsl:variable name="after" select="substring-after($text, $from)"/>
<xsl:variable name="prefix" select="concat($before, $to)"/>

<xsl:value-of select="$before"/>
<xsl:value-of select="$to"/>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$after"/>
<xsl:with-param name="from" select="$from"/>
<xsl:with-param name="to" select="$to"/>
</xsl:call-template>
</xsl:when>
<xsl:eek:therwise>
<xsl:value-of select="$text"/>
</xsl:eek:therwise>
</xsl:choose>
</xsl:template>

<!-- test the function -->
<xsl:template match="/">
<xsl:call-template name="replace-string">
<xsl:with-param name="text"
select="'Mary had a little lamb, little lamb, little lamb.'"/>
<xsl:with-param name="from" select="'little lamb'"/>
<xsl:with-param name="to">
<!-- X<xsl:value-of select="'little steak'"/>X -->
<b><xsl:value-of select="'little steak'"/></b>
</xsl:with-param>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet
 
M

Martin Honnen

Hvid said:
I want to highlight (make it bold) a word in some text I'm getting in
XML format. My plan was to replace the word with a bold (or span) tag
with the word within the tag. I've found the code below and it works
fine as long as I'm not adding tags around the to parameter. Can anyone
explain to me why it doesn't work with tags? And it needs to be XSLT 1.0.

You are using <xsl:value-of select="$to"/>, that outputs a text node
with the string value, it does not create elements.


Assuming you do not want to replace a substring but rather wrap it into
an element (e.g. b element) then use the following:

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

<xsl:template name="wrap">
<xsl:param name="text"/>
<xsl:param name="search"/>
<xsl:param name="element-name"/>

<xsl:choose>
<xsl:when test="contains($text, $search)">
<xsl:value-of select="substring-before($text, $search)"/>
<xsl:element name="{$element-name}">
<xsl:value-of select="$search"/>
</xsl:element>
<xsl:call-template name="wrap">
<xsl:with-param name="text" select="substring-after($text,
$search)"/>
<xsl:with-param name="search" select="$search"/>
<xsl:with-param name="element-name" select="$element-name"/>
</xsl:call-template>
</xsl:when>
<xsl:eek:therwise>
<xsl:value-of select="$text"/>
</xsl:eek:therwise>
</xsl:choose>
</xsl:template>

<xsl:template match="/">
<xsl:call-template name="wrap">
<xsl:with-param name="text" select="'Mary had a little lamb,
little lamb, little lamb.'"/>
<xsl:with-param name="search" select="'little lamb'"/>
<xsl:with-param name="element-name" select="'b'"/>
</xsl:call-template>
</xsl:template>

</xsl:stylesheet>
 
M

Martin Honnen

Martin said:
You are using <xsl:value-of select="$to"/>, that outputs a text node
with the string value, it does not create elements.

If you use xsl:copy-of as in

<xsl:template name="replace-string">
<xsl:param name="text"/>
<xsl:param name="from"/>
<xsl:param name="to"/>

<xsl:choose>
<xsl:when test="contains($text, $from)">

<xsl:variable name="before" select="substring-before($text, $from)"/>
<xsl:variable name="after" select="substring-after($text, $from)"/>
<xsl:variable name="prefix" select="concat($before, $to)"/>

<xsl:value-of select="$before"/>
<xsl:copy-of select="$to"/>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$after"/>
<xsl:with-param name="from" select="$from"/>
<xsl:with-param name="to" select="$to"/>
</xsl:call-template>
</xsl:when> <xsl:eek:therwise>
<xsl:value-of select="$text"/> </xsl:eek:therwise>
</xsl:choose> </xsl:template>

then I think you get what you want.
 
H

Hvid Hat

Thanks. Both your suggestions worked. Now I'm working on making the search
case-insensitive. Is there an easy way? Or can you guide me in the right
direction?

Hello Martin,
 
H

Hvid Hat

Hello Hvid,

Ok. Now I can replace the search string no matter what case it's in. Unfortunately
I haven't found a way to keep the original case of the search sting in the
text. Anyone? Here's my code:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:variable name="lcletters">abcdefghijklmnopqrstuvwxyz</xsl:variable>
<xsl:variable name="ucletters">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>

<xsl:template name="replace-string">
<xsl:param name="text"/>
<xsl:param name="from"/>
<xsl:param name="to"/>
<xsl:choose>
<xsl:when test="contains(translate($text, $ucletters, $lcletters), translate($from,
$ucletters, $lcletters))">
<xsl:variable name="before" select="substring-before(translate($text,
$ucletters, $lcletters), translate($from, $ucletters, $lcletters))"/>
<xsl:variable name="after" select="substring-after(translate($text, $ucletters,
$lcletters), translate($from, $ucletters, $lcletters))"/>
<xsl:variable name="prefix" select="concat($before, $to)"/>
<xsl:value-of select="$before"/>
<xsl:copy-of select="$to"/>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$after"/>
<xsl:with-param name="from" select="$from"/>
<xsl:with-param name="to" select="$to"/>
</xsl:call-template>
</xsl:when>
<xsl:eek:therwise>
<xsl:value-of select="$text"/>
</xsl:eek:therwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/">
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="'Mary had a little lamb, LITTLE LAMB,
x little lamb.'"/>
<xsl:with-param name="from" select="'little lamb'"/>
<xsl:with-param name="to">
<!-- X<xsl:value-of select="'little steak'"/>X -->
<b>
<xsl:value-of select="'little steak'"/>
</b>
</xsl:with-param>
</xsl:call-template>
</xsl:template>
 
D

David Carlisle

Hvid said:
Hello Hvid,

Ok. Now I can replace the search string no matter what case it's in.
Unfortunately I haven't found a way to keep the original case of the
search sting in the text. Anyone? Here's my code:


changing your variable assignents to

<xsl:variable name="i"
select="string-length(substring-before(translate($text, $ucletters,
$lcletters), translate($from, $ucletters, $lcletters)))"/>
<xsl:variable name="before"
select="substring($text,1,$i)"/>
<xsl:variable name="after"
select="substring($text,1+$i+string-length($from))"/>


will preserve the case of unmatched text (Mary in the example) If you
mean you need to replace LITTLE LAMB by <b>LITTLE STEAK</b> ie make the
replacement text match the case of the input, you have to work a bit
harrder, especially to say exactly what that means for mixed case text.

David

As I suspect you are aware this would be far easier in xslt 2.
 
D

David Carlisle

Hvid said:
Hello Hvid,

Ok. Now I can replace the search string no matter what case it's in.
Unfortunately I haven't found a way to keep the original case of the
search sting in the text. Anyone? Here's my code:


changing your variable assignents to

<xsl:variable name="i"
select="string-length(substring-before(translate($text, $ucletters,
$lcletters), translate($from, $ucletters, $lcletters)))"/>
<xsl:variable name="before"
select="substring($text,1,$i)"/>
<xsl:variable name="after"
select="substring($text,1+$i+string-length($from))"/>


will preserve the case of unmatched text (Mary in the example) If you
mean you need to replace LITTLE LAMB by <b>LITTLE STEAK</b> ie make the
replacement text match the case of the input, you have to work a bit
harrder, especially to say exactly what that means for mixed case text.

David

As I suspect you are aware this would be far easier in xslt 2.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Nested call-templates 1
XSL node as string 1
XSL :: page value assignment 0
newbie xsl / xslt question 2
URL string manipulation 1
Replace in XSLT 5
News Ticker 2
Inlining or de-xmlifying xml using XSLT 8

Members online

Forum statistics

Threads
473,968
Messages
2,570,153
Members
46,699
Latest member
AnneRosen

Latest Threads

Top