Re: [xsl] Escaping an apostrophe for JavaScript

Subject: Re: [xsl] Escaping an apostrophe for JavaScript
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Sun, 25 Feb 2001 08:36:39 +0000
Hi Frank,

> I can't seem to figure out any way of using translate or substring
> to convert the apostrophe to a backslash-apostrophe. There doesn't
> seem to be any way to locate the location of a substring within a
> string. Unless I loop it one character at a time.

You don't have to go over it one character at a time, but you do have
to recurse over it in some way.  The following template does it for

<xsl:template name="escape-apos">
   <xsl:param name="string" />
   <!-- create an $apos variable to make it easier to refer to -->
   <xsl:variable name="apos" select='"&apos;"'" />
      <!-- if the string contains an apostrophe... -->
      <xsl:when test='contains($string, $apos)' />
         <!-- ... give the value before the apostrophe... -->
         <xsl:value-of select="substring-before($string, $apos)" />
         <!-- ... the escaped apostrophe ... -->
         <!-- ... and the result of applying the template to the
                  string after the apostrophe -->
         <xsl:call-template name="escape-apos">
            <xsl:with-param name="string"
                            select="substring-after($string, $apos)" />
      <!-- otherwise... -->
         <!-- ... just give the value of the string -->
         <xsl:value-of select="$string" />

Things get a little more complicated if you need to escape other
characters as well (like double quotes and new lines).  You either
have three templates as above and call each on the result of the
previous, or have one template that recurses over both the bit before
and the bit after the relevant character.

> I was thinking perhaps I could make up a entity that is
> backslash-apostrophe, and then tell translate to replace apostrophe
> with this entity.

Entities are dealt with really low down the XML processing hierarchy.
The XSLT processor doesn't even see entities - all it sees is the
result of replacing an entity with the relevant string.

So if you have an entity:

  <!ENTITY test "\&apos;">

and then have:

  translate($string, "&apos;", "&test;")

then as far as the XSLT processor is concerned, this is *exactly* the
same as:

  translate($string, "'", "\'")

This will translate all apostrophes in your string with backslashes,
because the translate() function works on a character by character

Basically, you can't use translate() to search and replace anything
but single characters with other single characters.  You have to use a
recursive solution as above if you have something more complicated
than that.

> But I'm not sure where to put this DTD information in my XSL file. 
> I tried this:
> <?xml version="1.0" encoding="UTF-8"?>
> <!DOCTYPE xsl:stylesheet [
>         <!ENTITY test "\&apos;">
> <xsl:stylesheet xmlns:xsl="";
> ...
> </xsl:stylesheet>
> but I get this error:
> The element 'xsl:stylesheet' is used but not declared in the DTD/Schema

That's the right place to put it, but it looks as if putting the
DOCTYPE in a file automatically turns out a validating parser.  The
validating parser tries to validate the entire stylesheet (something
that is notoriously difficult, if not impossible), and gives you the
error because it comes across an element (xsl:stylesheet) that hasn't
been declared in the DTD.

Highly irritating if you just want to declare an entity.  I guess that
this is MSXML although I'm surprised because I thought they had
validation turned off by default.  You need to set validateOnParse to
false for the stylesheet.  Have a look at the MSXML SDK documentation
from for more details.

I hope that helps,


Jeni Tennison

 XSL-List info and archive:

Current Thread