[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: recursive string replace with tags

Subject: Re: recursive string replace with tags
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Wed, 2 Jul 2003 22:34:03 +0100
xsl string replace
Hi François,

Thanks for spelling out your problem so clearly.

> *The goal:*
> I'm inserting a <a> tag in my source document around each occurence
> of words mentioned in a dictionary (mygloss.xml).

OK, here goes. You need a recursive template that takes a string and a
list of replacements:

<xsl:template name="gloss">
  <xsl:param name="string" />
  <xsl:param name="gloss" select="document('mygloss.xml')/dic/item" />
  ...
</xsl:template>

There are two stopping conditions that should cause the template to
stop recursing: one is when $string is empty and one is when $gloss is
empty. In either case, giving the value of $string gives you what you
want:

<xsl:template name="gloss">
  <xsl:param name="string" />
  <xsl:param name="gloss" select="document('mygloss.xml')/dic/item" />
  <xsl:choose>
    <xsl:when test="$string and $gloss">
      ...
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$string" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

The next test is to see if the first word in the glossary appears in
the string:

<xsl:template name="gloss">
  <xsl:param name="string" />
  <xsl:param name="gloss" select="document('mygloss.xml')/dic/item" />
  <xsl:choose>
    <xsl:when test="$string and $gloss">
      <xsl:choose>
        <xsl:when test="contains($string, $gloss[1]/mot)">
          ...
        </xsl:when>
        <xsl:otherwise>
          ...
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$string" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

If the string doesn't contain the first word in the glossary, then the
result needs to be the result of calling the template on the string
with the rest of the words in the glossary:

<xsl:template name="gloss">
  <xsl:param name="string" />
  <xsl:param name="gloss" select="document('mygloss.xml')/dic/item" />
  <xsl:choose>
    <xsl:when test="$string and $gloss">
      <xsl:choose>
        <xsl:when test="contains($string, $gloss[1]/mot)">
          ...
        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="gloss">
            <xsl:with-param name="string" select="$string" />
            <xsl:with-param name="gloss"
                            select="$gloss[position() > 1]" />
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$string" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

If the string does contain the first word, then you need to do three
things:

  1. Process the string before the first word to see if it contains
     any of the remaining words in the glossary.

  2. Create an <a> element around the word to link to the translation.

  3. Process the string after the first word to see if it contains the
     word again.

Thus the completed template is:

<xsl:template name="gloss">
  <xsl:param name="string" />
  <xsl:param name="gloss" select="document('mygloss.xml')/dic/item" />
  <xsl:choose>
    <xsl:when test="$string and $gloss">
      <xsl:choose>
        <xsl:when test="contains($string, $gloss[1]/mot)">
          <xsl:variable name="mot" select="$gloss[1]/mot" />
          <xsl:call-template name="gloss">
            <xsl:with-param name="string"
                            select="substring-before($string, $mot)" />
            <xsl:with-param name="gloss"
                            select="$gloss[position() > 1]" />
          </xsl:call-template>
          <a href="{$gloss[1]/trans}">
            <xsl:value-of select="$mot" />
          </a>
          <xsl:call-template name="gloss">
            <xsl:with-param name="string"
                            select="substring-after($string, $mot)" />
            <xsl:with-param name="gloss" select="$gloss" />
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:call-template name="gloss">
            <xsl:with-param name="string" select="$string" />
            <xsl:with-param name="gloss"
                            select="$gloss[position() > 1]" />
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$string" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

To invoke the stylesheet use something like:

<xsl:template match="doc">
  <xsl:call-template name="gloss">
    <xsl:with-param name="string" select="string(.)" />
  </xsl:call-template>
</xsl:template>

I hope that gets you on the right track. Let us know if anything is
unclear.

Cheers,

Jeni

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


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


Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.