xslt and javascript

JavaScript

1. JavaScript in an XSL file
2. Incorporating javascript into a stylesheet
3. Scripting from XSLT
4. including javascript
5. Javascript escaping of single quote
6. Javascript escaping of single quote
7. Javascript Inclusion
8. Variable value from Javascript function
9. Javascript Function with less than sign
10. Including javascript in the output file
11. Inserting javascript
12. Script element in Internet Explorer
13. Javascript braces and AVT's
14. Running msxsl from jscript
15. Escape a single quote

1.

JavaScript in an XSL file

Mike Brown



> I have an XSL file that I use to display my XML data. The XSL file contains
> some JavaScript. How can
> I get XSL to understand that this is code and not some tagging? 
> I have defined my
> script block with LANGUAGE="JavaScript" inside the HEAD block which is
> inside the <xsl:template match="/"> block.
> 
> I have gotten it to work when I replace the < sign with &lt; which is pretty
> ugly!
	

Ugliness aside, it is absolutely correct.

You don't have the option of making your XSLT be malformed XML. So you *must* escape it, or use a <![CDATA[ ... ]]> section, which serves no purpose but to make it so you don't have to escape the text in that section. This escaping is input-side only; it has no bearing on what the character data actually means, nor on the output after XSLT processing.

Having unescaped markup characters in 'script data' type elements in HTML is an option offered by HTML for the convenience of document authors -- the 'natural' way is to escape every markup character that's not being used as markup. HTML is nice about it and says that unescaped markup character in certain elements is required to be treated exactly the same as an escaped markup character. That's why you can get away with not escaping it.

A stylesheet is not a literal specification for output. Escape the not-being-used-as-markup markup characters on the way in, and let the processor escape them on the way back out. Internally, they aren't escaped at all, but you wouldn't know that by looking at just the input and output.

If you feel that the text nodes your stylesheet is creating must be serialized without markup characters being escaped (which could create malformed output, if you think about it), then you have the option of using the disable-output-escaping="yes" attribute on xsl:value-of or xsl:text instructions that create the text nodes. I would not worry about it, though. Browsers are required to handle escaped script data.

2.

Incorporating javascript into a stylesheet

Ben Robb

You may have a xsl page something like:

<xsl:stylesheet ...>
<xsl:template match="/">
<html>
 <head>
 <script language="Javascript"><![CDATA[
	function myAlert() {
  		window.status="Welcome to my homepage";
	}
 ]]></script>
 </head>
 <body>
<xsl:for-each select="main_news/news/title">
	<a href="Javascript:myAlert()">
	<li/><xsl:value-of select="./@headline"/></a>
		</xsl:for-each>
 </body>
</html>
</xsl:template>
</xsl:stylesheet>

3.

Scripting from XSLT

Chris Bayes.

This example creates a script block with a namepace prefix of "user" that contains a function called "xml" that takes a node-list as an argument. Later, this function is called from the select attribute of <xsl:value-of>.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:user="http://mycompany.com/mynamespace"
                version="1.0">
  <msxsl:script language="JScript" implements-prefix="user">
    function xml(nodelist) {
      return nodelist.nextNode().xml;
    }
  </msxsl:script>

  <xsl:template match="/">
    <xsl:value-of select="user:xml(.)"/>
  </xsl:template>
</xsl:stylesheet>

4.

including javascript

Jeni Tennison

>	<xsl:element name="A">
>		<xsl:attribute name="href">
>
javascript:Popup=window.open('','IntlPopup','alwaysRaised=1,dependent=1,
height=300,location=0,menubar=1,personalbar=0,scrollbars=0,status=0,
toolbar=0,width=590,resizable=0');
>			Popup.focus();
>			Popup.document.write('
>			<TABLE>
>			<xsl:copy-of select="tr"/>
>			</TABLE>
>			');
>		</xsl:attribute>
>			Enlarge this table
>	</xsl:element>

If you look at the code above, you'll see that you're setting the @href attribute on the generated A element to a string inside which (as far as the XSLT processor's concerned) you're creating a TABLE element, and a number of copies of other elements as well.

XSLT processors justifiably won't let you put elements within attribute content: you have to escape the < and >. This means that you can't simply copy the tr elements across - you have to output them as serialised XML. I wrote this template earlier today for a similar problem:

<xsl:template match="*" mode="serialise">
  <xsl:text />&lt;<xsl:value-of select="name()" />
  <xsl:for-each select="@*">
    <xsl:text> </xsl:text>
    <xsl:value-of select="name()" />
    <xsl:text />="<xsl:value-of select="." />"<xsl:text />
  </xsl:for-each>
  <xsl:text>&gt;</xsl:text>
  <xsl:apply-templates mode="serialise" />
  <xsl:text />&lt;/<xsl:value-of select="name()" />&gt;<xsl:text />
</xsl:template>

So, you can either replace the above with:

	<xsl:element name="A">
		<xsl:attribute name="href">
javascript:Popup=window.open
('','IntlPopup','alwaysRaised=1,dependent=1,height=300,
location=0,menubar=1,personalbar=0,scrollbars=0,
status=0,toolbar=0,width=590,resizable=0');
			Popup.focus();
			Popup.document.write('
			&lt;TABLE&gt;
			<xsl:apply-templates select="tr" mode="serialise" />
			&lt;/TABLE&gt;
			');
		</xsl:attribute>
			Enlarge this table
	</xsl:element>

Or you can use CDATA sections so that you don't have to worry about escaping the < and > around the TABLE element:

	<xsl:element name="A">
		<xsl:attribute name="href">

<![CDATAjavascript:Popup=window.open
('','IntlPopup','alwaysRaised=1,dependent=1,height=300,location=0,
menubar=1,personalbar=0,scrollbars=0,status=0,toolbar=0,width=590,
resizable=0');
		Popup.focus();
		Popup.document.write('
		<TABLE>]]>
		<xsl:apply-templates select="tr" mode="serialise" />
		<![CDATA[</TABLE>
		');]]>
	</xsl:attribute>
		Enlarge this table
	</xsl:element>

The resultant output will be:

<A
href="javascript:Popup=window.open
('','IntlPopup','alwaysRaised=1,dependent=1,height=300,location=0,
menubar=1,personalbar=0,scrollbars=0,status=0,toolbar=0,width=590,
resizable=0');
	Popup.focus();
	Popup.document.write('
	&lt;TABLE&gt;
	&lt;tr&gt;...&lt;/tr&gt;
	&lt;/TABLE&gt;
	');">Enlarge this table</A>

but the Javascript processor will see the unescaped string:

javascript:Popup=window.open
('','IntlPopup','alwaysRaised=1,dependent=1,height=300,location=0,
menubar=1,personalbar=0,scrollbars=0,status=0,toolbar=0,width=590,
resizable=0');
	Popup.focus();
	Popup.document.write('
	<TABLE>
	<tr>...</tr>
	</TABLE>
	');

and therefore 'do the right thing'. Or should, anyway.

Additional note from David Carlisle:

> But what is the purpose of empty <xsl:text /> instructions?

It's the same as putting the characters inside a non empty xsl:text, but saves a few keystrokes. Note the end result is the same, the white space used to indent the stylesheet is in nodes that only have white space so is stripped.

     <xsl:value-of select="name()" />
     <xsl:text />="<xsl:value-of

is effectively same as

     <xsl:value-of select="name()" />
     <xsl:text>="<xsl:text><xsl:value-of

but both of those are not the same as

     <xsl:value-of select="name()" />
     ="<xsl:value-of

which puts a newline and some spaces before the = in the output tree.

Mike Kay goes on:

An empty <xsl:text/> instruction splits a text node into two, typically making one of them a whitespace-only node that will be stripped from the stylesheet.

Useful e.g. in
<xsl:attribute>
<xsl:text/>[<xsl:value-of select="$x"/>]<xsl:text/>
</xsl:attribute>

to prevent newlines in the output. You can't put an <xsl:text> element around the <xsl:value-of>, it's not allowed to contain child elements, and the alternative of

<xsl:text>[</xsl:text><xsl:value-of select="$x"/><xsl:text>]</xsl:text>

is even uglier.

5.

Javascript escaping of single quote

Christopher R. Maden



>I have some JavaScript functions that, on click of a glossed word, open a
>new window and writes to it with document.write.  That all works fine except
>there is potential for it to break if the defintion contains a single quote.
>Is there some way to apply-templates and search for the single quote
>character and prepend the js escape character "\" to the single quote?
	
<xsl:template name="fixQuotes">
   <xsl:param name="do.quote"/>
   <xsl:param name="string"/>
   <xsl:choose>
     <xsl:when test="$do.quote">
       <xsl:choose>
         <xsl:when test="contains($string, &quot;'&quot;)">
           <xsl:value-of
             select="substring-before($string, &quot;'&quot;)"/>
           <xsl:text>\'</xsl:text>
           <xsl:call-template name="fixQuotes">
             <xsl:with-param name="do.quote" select="$do.quote"/>
             <xsl:with-param name="string"
               select="substring-after($string, &quot;'&quot;)"/>
           </xsl:call-template>
         </xsl:when>
         <xsl:otherwise>
           <xsl:value-of select="$string"/>
         </xsl:otherwise>
       </xsl:choose>
     </xsl:when>
     <xsl:otherwise>
       <xsl:value-of select="$string"/>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

Chris McGrath provides a Microsoft Javascript alternative.

<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       xmlns:msxsl="urn:schemas-microsoft-com:xslt"
       xmlns:user="user"
       exclude-result-prefixes="msxsl user">

<xsl:output method="html" indent="no" />

<msxsl:script language="JavaScript" implements-prefix="user">
<![CDATA[
	function encodeString(str_in) {
		return escape(str_in);
	}
]]>
</msxsl:script>

.....

<xsl:template match="Blah">
 <xsl:element name="a">
  <xsl:attribute name="id"><xsl:value-of
select="user:encodeString(string(@name))"/></xsl:attribute>
 </xsl:element>
</xsl:template>

.......

</xsl:stylesheet>

6.

Javascript escaping of single quote

Christopher R. Maden


>I have some JavaScript functions that, on click of a glossed word, open a
>new window and writes to it with document.write.  That all works fine except
>there is potential for it to break if the defintion contains a single quote.
>Is there some way to apply-templates and search for the single quote
>character and prepend the js escape character "\" to the single quote?
	
&lt;xsl:template name="fixQuotes">
   &lt;xsl:param name="do.quote"/>
   &lt;xsl:param name="string"/>
   &lt;xsl:choose>
     &lt;xsl:when test="$do.quote">
       &lt;xsl:choose>
         &lt;xsl:when 
	  test="contains($string, &amp;quot;'&amp;quot;)">
           &lt;xsl:value-of
         select="substring-before($string, &amp;quot;'&amp;quot;)"/>
           &lt;xsl:text>\'&lt;/xsl:text>
           &lt;xsl:call-template name="fixQuotes">
             &lt;xsl:with-param name="do.quote" select="$do.quote"/>
             &lt;xsl:with-param name="string"
        select="substring-after($string, &amp;quot;'&amp;quot;)"/>
           &lt;/xsl:call-template>
         &lt;/xsl:when>
         &lt;xsl:otherwise>
           &lt;xsl:value-of select="$string"/>
         &lt;/xsl:otherwise>
       &lt;/xsl:choose>
     &lt;/xsl:when>
     &lt;xsl:otherwise>
       &lt;xsl:value-of select="$string"/>
     &lt;/xsl:otherwise>
   &lt;/xsl:choose>
&lt;/xsl:template>

Chris McGrath provides a Microsoft Javascript alternative.

&lt;?xml version='1.0'?>
&lt;xsl:stylesheet version="1.0"
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       xmlns:msxsl="urn:schemas-microsoft-com:xslt"
       xmlns:user="user"
       exclude-result-prefixes="msxsl user">

&lt;xsl:output method="html" indent="no" />

&lt;msxsl:script language="JavaScript" implements-prefix="user">
&lt;![CDATA[
	function encodeString(str_in) {
		return escape(str_in);
	}
]]>
&lt;/msxsl:script>

.....

&lt;xsl:template match="Blah">
 &lt;xsl:element name="a">
  &lt;xsl:attribute name="id">&lt;xsl:value-of
select="user:encodeString(string(@name))"/>&lt;/xsl:attribute>
 &lt;/xsl:element>
&lt;/xsl:template>

.......

&lt;/xsl:stylesheet>

7.

Javascript Inclusion

Jeni Tennison

You can mix namespaces to use the MSXML 'msxsl:script' extension element *as well as* all the really cool stuff you get with XSLT 1.0.

The MSXML3.0 SDK documentation, which you can get from msdn.microsoft.com, tells you about what you can do with msxsl:script. But here's a small example.

<!-- include in the xsl:stylesheet element:
     (a) the version attribute as usual
     (b) the XSLT namespace declaration as usual
     (c) the MSXSL namespace declaration
     (d) a namespace declaration to identify your functions
     (e) the 'extension-element-prefixes' attribute to give the
         namespace prefixes that indicate extension elements
         (i.e. 'msxsl')
     (f) the 'exclude-result-prefixes' attribute to indicate the
         namespaces that aren't supposed to be part of the result
         tree (i.e. 'foo') -->
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:foo="http://www.broadbase.com/foo"
                extension-element-prefixes="msxsl"
                exclude-result-prefixes="foo">
<!-- do whatever output you want - you can use full XSLT functionality
     -->
<xsl:output method="html" />
<!-- define the Javascript functions that you want to include within
     a msxsl:script element.
     - language indicates the scripting language
     - implements-prefix gives the namespace prefix that you declared
       for your function (i.e. foo) -->
<msxsl:script language="javascript"
              implements-prefix="foo">
              
   <!-- it's often helpful to use a CDATA section so you don't have to
        worry about escaping less-than signs or anything -->
   <![CDATA[

   <!-- define your functions -->
   function today() {
      today = new Date();
      return today.toLocaleString();
   }

   ]]>
</msxsl:script>

<xsl:template match="/">
   <p>
      This page brought to you on
      <!-- call your functions using the prefix that you've used (i.e.
           foo) anywhere you can normally use an XPath function, but
           make sure it's returning the right kind of object -->
      <xsl:value-of select="foo:today()" />.
   </p>
</xsl:template>
                
</xsl:stylesheet>

When XSLT 1.1 comes along, it's fairly likely that you'll just be able to do a global search & replace on 'msxsl:script' for 'xsl:script' and be XSLT 1.1 compliant.

> I have to write simple functions in JavaScript like obtaining month
> name from the number of the month,

Since you mention this: the classic way of doing this in XSLT is to add some XML defining the months within the stylesheet itself:

<foo:months>
   <foo:month>January</foo:month>
   <foo:month>February</foo:month>
   <foo:month>March</foo:month>
   ...
</foo:months>

You then get the name of the month by accessing this XML using the document() function:

<xsl:value-of
  select="document('')/*/foo:months/foo:month[$month-number]" />

As you are using MSXML-specific code anyway, you could alternatively do this by defining a variable:

<xsl:variable name="months">
  <month>January</month>
  <month>February</month>
  <month>March</month>
  ...
</xsl:variable>

and retrieving it with an MSXML-specific extension function, i.e. msxsl:node-set:

<xsl:value-of
  select="msxsl:node-set($months)/month[$month-number]" />

I mention this to compare and contrast with msxsl:script: both are extensions over and above the functionality of XSLT 1.0, msxsl:script an extension element and msxsl:node-set() an extension function. To use them you just have to use a processor that understands them, declare the relevant namespace, and specify that it's an extension namespace, and you're all set.

8.

Variable value from Javascript function

Jeni Tennison


> please, is there any way to affect an xml variable with the output
> return of a JavaScript function ?
	

Yes, but be aware that Javascript isn't incorporated into XSLT until XSLT 1.1 or unless you're using MSXML. The first thing that you need to do is to declare the function within an msxsl:script element:

<msxsl:script language="javascript"
              implements-prefix="foo">
   function retrieveData() {
      return true;
   }
</msxsl:script>

In order to do this, you need to declare the 'msxsl' namespace (urn:schemas-microsoft-com:xslt) and your own 'foo' namespace. The 'msxsl' namespace needs to be declared as an extension element prefix (using the extension-element-prefixes attribute on xsl:stylesheet) and the 'foo' namespace should be excluded from your result tree (using the exclude-result-prefixes or extension-element-prefixes attribute on xsl:stylesheet).

Once you've declared the Javascript functions like this, you can call them within any XPath expression using, e.g.:

  foo:retrieveData()

So, to set $my_var to have the value returned by the function, use:

  <xsl:variable name="my_var" select="foo:retrieveData()" />

There's nothing in XSLT that interprets the content of an element as something to run: calls to functions are *always* in attribute values.

9.

Javascript Function with less than sign

Jeni Tennison


> I had to use some javascript functions that involves
> for(i=0;a&&i<a.length&&(x=a[i])&&
>   x.oSrc;i++) x.src=x.oSrc;
	

OK. To understand how to do this, you have to learn to distinguish between the *physical* document and the *logical* document. In a logical document, the above is the string:

  for(i=0;a&&i<a.length&&
(x=a[1])&&x.oSrc;i++) x.src=x.oSrc;

However, there are certain characters that are special to XML, especially '<' and '&'. XML uses entities to escape them when it writes a physical document: '<' is serialised as '&lt;' and '&' as '&amp;' for example. So *physically* the above string can be represented in XML as:

  for(i=0;a&amp;&amp;i&lt;a.length
&amp;&amp;(x=a[1])&amp;&amp;x.oSrc;i++) x.src=x.oSrc;

When an XML parser reads that, it creates the string that's above, because it unescapes the relevant characters. You could just as well replace *every* character in that string with a character entity reference, and it would make not one jot of difference to the XML application using the string (e.g. XSLT processor, XML-aware browser). For example, I could replace all the 'a' with their character entity reference:

  for(i=0;&#x61;&amp;&amp;i&lt;&#x61;
	.length&amp;&amp;(x=&#x61;[1])&amp;&amp;x.
	oSrc;i++) x.src=x.oSrc;

Because escaping characters leads to long and unreadable XML, there's a shorthand way of doing the same thing - using CDATA sections. Within a CDATA section, all characters are treated just as characters. So another XML version of the string is:

  <![CDATA[for(i=0;a&&i<a.
	length&&(x=a[1])&&x.oSrc;i++) x.src=x.oSrc;]]>

So what does this all mean for you? Well, it's got two implications, one for your XSLT stylesheet and one for the output that it produces.

Your XSLT stylesheet must be well-formed XML. So all the special characters have to be escaped within it, which you can do (as discussed above) either with entities or with a CDATA section. If you're not dynamically generating the Javascript with XSLT, it's probably worth using a CDATA section for comfort. So, in your XSLT stylesheet you need to have something like:

  <head>
     <script language="Javascript">
        <![CDATA[
          ...
          for(i=0;a&&i<a.length&&
	  (x=a[1])&&x.oSrc;i++) x.src=x.oSrc;
          ...
        ]]>
     </script>
  </head>

You don't want to place it in a comment because comments in your XSLT stylesheet won't be outputted into your result tree, and you want the Javascript to show up in the result.

Since you are outputting HTML, I guess that you are using the 'html' output method by setting:

  <xsl:output method="html" />

or by having an 'html' element as the top-most element in your result tree?

If you are using the HTML output method, then the Javascript will be outputted *unescaped* as:

  <head>
     <script language="Javascript">
          ...
          for(i=0;a&&i<a.length&&(x=a[1])
	  &&x.oSrc;i++) x.src=x.oSrc;
          ...
     </script>
  </head>

This is because HTML accepts unescaped text content in script elements.

If you are using the XML output method, perhaps because you're producing XHTML, then the Javascript will be outputted *escaped* because you're producing well-formed XML, as:

  <head>
     <script language="Javascript">
          ...
          for(i=0;a&amp;&amp;i&lt;a.length&amp;
	  &amp;(x=a[1])&amp;&amp;x.oSrc;i++) x.src=x.oSrc;
          ...
     </script>
  </head>

If you want to make that more readable, you can tell the XSLT processor that you want the script element to have as its content a CDATA section, using:

  <xsl:output method="xml" cdata-section-elements="script" />

If you do this, a CDATA section will be automatically used within the script element, so the output will be:

  <head>
     <script language="Javascript">
        <![CDATA[
          ...
          for(i=0;a&&i<a.length&&
	  (x=a[1])&&x.oSrc;i++) x.src=x.oSrc;
          ...
        ]]>
     </script>
  </head>

Some people have suggested using disable-output-escaping. Disabling output escaping is *hardly ever* necessary, and often dangerous because it allows you to produce documents that aren't well-formed. You should avoid it if you can, and you definitely can in this case.

10.

Including javascript in the output file

Jeni Tennison



  > I been brought into an existing project that is XML/XSL based. Even
  > with limited XSL experience, I see a huge maintenance nightmare
  > evolving. According to the consultants working on the project with
  > us, they have found no way to put needed client side JavaScript
  > functions into an include file. So all JavaScript functions are
  > being duplicated on every page. Since the maintenance of this
  > product will fall on my shoulders, I want to find a better solution.
  > Is there a way to include a .js file that the XSLT parser will
  > accept? Thank you for your time.
  

It's unclear from your description whether you're talking about including the Javascript in the *output* of the transformation (which I assume is HTML) or in the stylesheet itself (i.e. you're using msxsl:script to get extension functions).

If you're generating HTML, then you can link to an external JavaScript document by generating a script element in the same way as you would if you were writing the HTML document directly. In other words, in your XSLT you should have a literal result element that looks something like:

    <script language="javascript" type="text/javascript"
            href="script.js" />

The href is likely to be resolved relative to the XML document that's being transformed (at a guess), not the stylesheet.

If you're using msxsl:script to define extension functions, then they're right, msxsl:script doesn't have the facility to point to an external Javascript file. However, you can put the msxsl:script element in its own stylesheet (e.g. script.xsl) and then include it into as many other stylesheets as you like using xsl:include:

  <xsl:include href="script.xsl" />

Alternatively, you could use XML entities. Wrap the content of the Javascript file in a CDATA section (so that you don't have to escape all the <s and &s within it), and then declare the entity in the stylesheet that you want to use it in:

  <!DOCTYPE xsl:stylesheet [
  <!ENTITY script SYSTEM 'script.js'>
  ]>

and then use &script; to insert the script into the file as desired.

11.

Inserting javascript

Jeni Tennison


> In xsl, how can I insert a JavaScript? I have tried:
>
> <Script language="JavaScript" src="functions.js"></script>
>
> But it didn't work. Can someone help?

I've found that Internet Explorer doesn't like script elements that don't have any content (perhaps because with the XML output method they don't have a close tag). You can get around the problem by inserting a comment within the script element:

  <script type="text/javascript" src="functions.js">
    <!-- comment inserted for Internet Explorer -->
  </script>

You can generate this script element from XSLT with:

  <script type="text/javascript" src="functions.js">
    <xsl:comment> comment inserted for Internet Explorer </xsl:comment>
  </script>

12.

Script element in Internet Explorer

Jeni Tennison



> In xsl, how can I insert a JavaScript? I have tried:
>
> <Script language="JavaScript" src="functions.js"></script>
>
> But it didn't work. Can someone help?

I've found that Internet Explorer doesn't like script elements that don't have any content (perhaps because with the XML output method they don't have a close tag). You can get around the problem by inserting a comment within the script element:

  <script type="text/javascript" src="functions.js">
    <!-- comment inserted for Internet Explorer -->
  </script>

You can generate this script element from XSLT with:

  <script type="text/javascript" src="functions.js">
    <xsl:comment> comment inserted for Internet Explorer </xsl:comment>
  </script>

13.

Javascript braces and AVT's

Michael Kay



> What is the preferred method for including javascript braces, 
> such that

> <body onload="if (true) { alert('foo'); alert('bar') }">

> doesn't get interpreted as an AVT?

Write them as "{{" and "}}".

14.

Running msxsl from jscript

Jonathan Marsh


/*

  transform.js
  
  Windows Scripting Host file for performing command-line XSL
  transformations.
  
  Parameters:  source-file stylesheet-file output-file
  
  Author: Jonathan Marsh 
  
*/

var args = WScript.arguments;
if (args.length != 3)
  alert("parameters are: source-file stylesheet-file output-file");
else
{
  var ofs = WScript.CreateObject("Scripting.FileSystemObject");

  var scriptpath = ofs.getParentFolderName(WScript.scriptFullName);
  var source = scriptpath + "\\" + args.item(0);
  var stylesheet = scriptpath + "\\" + args.item(1);
  var dest = scriptpath + "\\" + args.item(2);

  var oXML = new ActiveXObject("MSXML.DOMDocument");
  oXML.validateOnParse = false;
  oXML.async = false;
  oXML.load(source);

  var oXSL = new ActiveXObject("MSXML.DOMDocument");
  oXSL.validateOnParse = false;
  oXSL.async = false;
  oXSL.load(stylesheet);

  var oFile = ofs.CreateTextFile(dest);
  oFile.Write(oXML.transformNode(oXSL));
  oFile.Close();
}

15.

Escape a single quote

Tom Passin

Here is a template I have used to javascript-escape a single-quote. The template works its way through the entire string that it is passed as a parameter. In xslt 1.0 you have to do this recursively. You need to remember that if you use, say, substring-after, and you get no match, nothing is returned (you might think you would get the whole string, but you do not). Handling those cases adds some complexity.

[The slightly odd formatting, with the closing angle brackets at the start of new lines, is the simplest way I have found to make __sure__ that no unwanted whitespace sneaks into expressions like these. Experts may say you can avoid stray whitespace easily without resorting to tricks like this, but I have been bit too many times trying to format javascript properly. This method may be overkill, but it works (there is __no__ extra whitespace between elements in the template so there is no way whitespace nodes can accidentally get added). Yet it is formatted almost the same as I would normally format the code].

<xsl:template name='fixapos'
><xsl:param name='data'
/><xsl:variable name='rest' select='substring-after($data,"&apos;")'
/><xsl:variable name='first'><xsl:choose><xsl:when
test='contains($data,"&apos;")'
><xsl:value-of select='substring-before($data,"&apos;")'
/></xsl:when><xsl:otherwise><xsl:value-of select='$data'
/></xsl:otherwise></xsl:choose></xsl:variable><xsl:value-of
select='$first'
/><xsl:if test='$rest'>\&apos;<xsl:call-template name='fixapos'
><xsl:with-param name='data'
     select='$rest'/></xsl:call-template></xsl:if></xsl:template>