Replace String

Discussion in 'XML' started by Hvid Hat, Feb 13, 2008.

  1. Hvid Hat

    Hvid Hat Guest

    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
     
    Hvid Hat, Feb 13, 2008
    #1
    1. Advertising

  2. Hvid Hat wrote:

    > 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>



    --

    Martin Honnen
    http://JavaScript.FAQTs.com/
     
    Martin Honnen, Feb 13, 2008
    #2
    1. Advertising

  3. Martin Honnen wrote:
    > Hvid Hat wrote:
    >
    >> 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.


    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.


    --

    Martin Honnen
    http://JavaScript.FAQTs.com/
     
    Martin Honnen, Feb 13, 2008
    #3
  4. Hvid Hat

    Hvid Hat Guest

    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,

    > Martin Honnen wrote:
    >
    >> Hvid Hat wrote:
    >>
    >>> 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.
    >>

    > 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.
    >
     
    Hvid Hat, Feb 13, 2008
    #4
  5. Hvid Hat

    Hvid Hat Guest

    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>
    </xsl:stylesheet>


    > 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,
    >
    >> Martin Honnen wrote:
    >>
    >>> Hvid Hat wrote:
    >>>
    >>>> 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.
    >>>

    >> 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
     
    Hvid Hat, Feb 13, 2008
    #5
  6. Hvid Hat wrote:
    > 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.

    --
    http://dpcarlisle.blogspot.com
     
    David Carlisle, Feb 14, 2008
    #6
  7. Hvid Hat wrote:
    > 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.

    --
    http://dpcarlisle.blogspot.com
     
    David Carlisle, Feb 14, 2008
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Brian Blais
    Replies:
    1
    Views:
    395
    Bruno Desthuilliers
    Jun 27, 2006
  2. Greg Ewing
    Replies:
    2
    Views:
    357
    Dieter Maurer
    Jun 29, 2006
  3. Alun
    Replies:
    3
    Views:
    4,580
    Masudur
    Feb 18, 2008
  4. Prasad S
    Replies:
    2
    Views:
    245
    Dr John Stockton
    Aug 27, 2004
  5. V S Rawat
    Replies:
    5
    Views:
    319
    Richard Cornford
    Jul 3, 2007
Loading...

Share This Page