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

Re: Parameter substitution

Subject: Re: Parameter substitution
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Wed, 19 Dec 2001 18:10:10 +0000
xsl param substitution
Hi Curtis,

> Below is given a fragment from an XML document. Of note are the
> contents of the <ErrorText> nodes; the first one has a value of "%1
> %2 is not a valid date format.".
>
> My task, (you guessed it) is to replace each %1, %2 etc.. with a
> string built from the correspondong ErrorParameter (formatted nicely
> of course) . Being relatively new to XSLT, I can't think of a way to
> accomplish this in a generic manner. Has anyone got any ideas? I
> can't think of an approach that will actually work!

It's a little tedious because XPath string-handling isn't the best
(roll on regexps), but it's certainly possible. To work through the
string, you need a recursive template; it needs to take the string in
which you're replacing parameter references, and a list of parameters
that you want to replace the references with:

<xsl:template name="substituteParameters">
  <xsl:param name="string" />
  <xsl:param name="parameters" select="/.." />
  ...
</xsl:template>

You need to work through the string a bit at a time. If the string
doesn't contain any % characters, then you know that you can just
output the string with no changes, so that's the basic test on which
the template hinges:

<xsl:template name="substituteParameters">
  <xsl:param name="string" />
  <xsl:param name="parameters" select="/.." />
  <xsl:choose>
    <xsl:when test="contains($string, '%')">
      ...
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="." />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Now, given that you have a string with a % in it, you want to output:

 - the string up to the %
 - the parameter in the position indicated by the number after the %
 - the result of calling this same template on the rest of the string
   (after the number)

The first bit's easy - you can use the substring-before() function to
get the bit before the %:

<xsl:template name="substituteParameters">
  <xsl:param name="string" />
  <xsl:param name="parameters" select="/.." />
  <xsl:choose>
    <xsl:when test="contains($string, '%')">
      <xsl:value-of select="substring-before($string, '%')" />
      ...
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="." />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

The second bit's a little more complicated - you need to get the
number after the %. If you can guarantee that there aren't going to be
more than 9 parameters, then you only need to get the first character
after the %, so I'll assume that's the case (let me know if it's not).
So you can use the following to get the first character after the %:

  substring(substring-after($string, '%'), 1, 1)

That gives you (a string representation of) a number, which you can
use to index into the parameters passed as the value of the
$parameters parameter:

  $parameters[position() =
              substring(substring-after($string, '%'), 1, 1)]

or:

  $parameters[number(substring(substring-after($string, '%'), 1, 1))]

I'd apply templates to this parameter - you can have a template
matching ErrorParameter elements that does the relevant pretty
formatting:

<xsl:template name="substituteParameters">
  <xsl:param name="string" />
  <xsl:param name="parameters" select="/.." />
  <xsl:choose>
    <xsl:when test="contains($string, '%')">
      <xsl:value-of select="substring-before($string, '%')" />
      <xsl:apply-templates
        select="$parameters[number(substring(
                                     substring-after($string, '%'),
                                     1, 1))]" />
        ...
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="." />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Finally, the recursive call to the template needs to pass in the same
set of parameters whilst amending the string to being the 'rest' of
the substring after the '%':

<xsl:template name="substituteParameters">
  <xsl:param name="string" />
  <xsl:param name="parameters" select="/.." />
  <xsl:choose>
    <xsl:when test="contains($string, '%')">
      <xsl:value-of select="substring-before($string, '%')" />
      <xsl:apply-templates
        select="$parameters[number(substring(
                                     substring-after($string, '%'),
                                     1, 1))]" />
      <xsl:call-template name="substituteParameters">
        <xsl:with-param name="string"
          select="substring(substring-after($string, '%'), 2)" />
        <xsl:with-param name="parameters" select="$parameters" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="." />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

To call it, you'd do something like the following (assuming that
SynchError is the current node):

  <xsl:call-template name="substituteParameters">
    <xsl:with-param name="string" select="ErrorText" />
    <xsl:with-param name="parameters" select="ErrorParameter" />
  </xsl:call-template>

Having said all of that, you would be a lot better off if you could
change the XML structure so that you used elements to indicate where
the parameters should be inserted. Something like:

  <ErrorText>
    <Insert param="1" /> <Insert param="2" /> is not a valid date
    format.
  </ErrorText>

That way, you could just apply templates to the content of the
ErrorText element and use templates matching Insert elements to insert
the value of the relevant parameter.

I hope that helps,

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.