© 2004 Microsoft Corporation. All rights reserved.

Figure 1 Processing the Equation with JScript
function processEquation(ops) {
  var result=0, i;
  for (i=0; i<ops.length; i++) {
    switch(ops[i].nodeName) {
      case "add":
        result += parseFloat(ops[i].text); break;
      case "sub":
        result -= parseFloat(ops[i].text); break;
      case "mul":
        result *= parseFloat(ops[i].text); break;
      case "div":
        result = result / parseFloat(ops[i].text); break;
      case "mod":
        result = result % parseFloat(ops[i].text); break;
      default:
        return "Unsupport operation";
     }
   }
   return result;
}
Figure 2 Processing the Equation with XSLT
<?xml version="1.0" encoding="utf-8"?>
<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:output method="text"/>
  <xsl:template name="processEquation">
    <xsl:param name="ops" select="/.."/>
    <xsl:choose>
      <xsl:when test="$ops">
        <xsl:variable name="last" select="$ops[last()]"/>
        <xsl:variable name="total">
          <xsl:call-template name="processEquation">
            <xsl:with-param name="ops" 
               select="$ops[position()!=last()]"/>
          </xsl:call-template>
        </xsl:variable>
        <xsl:choose>
          <xsl:when test="name($last)='add'">
            <xsl:value-of select="$total + $last"/>
          </xsl:when>
          <xsl:when test="name($last)='sub'">
            <xsl:value-of select="$total - $last"/>
          </xsl:when>
          <xsl:when test="name($last)='mul'">
            <xsl:value-of select="$total * $last"/>
          </xsl:when>
          <xsl:when test="name($last)='div'">
            <xsl:value-of select="$total div $last "/>
          </xsl:when>
          <xsl:when test="name($last)='mod'">
            <xsl:value-of select="$total mod $last"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:message terminate="yes">
                Unsupported operation</xsl:message>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  <xsl:template match="/">
    <!-- root template -->
    result: 
      <xsl:call-template name="processEquation">
        <xsl:with-param name="ops" select="/equation/*"/>
      </xsl:call-template>
  </xsl:template>
</xsl:transform>
Figure 3 Processing the Equation with XSLT + JScript
<?xml version="1.0" encoding="utf-8"?>
<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:ms="urn:schemas-microsoft-com:xslt" 
  xmlns:usr="urn:the-xml-files:xslt"
>
  <xsl:output method="text"/>
  <ms:script language="JScript" implements-prefix="usr">
    <![CDATA[
    function processEquation(ops) {
      var result=0, i;
      for (i=0; i<ops.length; i++) {
        switch(ops[i].nodeName) {
          case "add":
            result += parseFloat(ops[i].text); break;
          case "sub":
            result -= parseFloat(ops[i].text); break;
          case "mul":
            result *= parseFloat(ops[i].text); break;
          case "div":
            result = result / parseFloat(ops[i].text); break;
          case "mod":
            result = result % parseFloat(ops[i].text); break;
          default:
            return "Unsupport operation";
         }
       }
       return result;
    }
    ]]>
  </ms:script>
  <xsl:template match="/">
    <!-- root template -->
    result: <xsl:value-of 
               select="usr:processEquation(/equation/*)"/>
  </xsl:template>
</xsl:transform>
Figure 4 A Transformation
<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:out="http://www.w3.org/1999/xhtml"
  xmlns:ext="http://example.org/extension"
  extension-element-prefixes="ext"
>
  <xsl:template match="/">
    <out:html>
      <xsl:choose>
        <xsl:when 
          test="element-available('ext:doSomeFunkyMagic')">
          <ext:doSomeFunkyMagic/>
        </xsl:when>
        <xsl:otherwise>
          <!-- backup functionality goes here -->
          •••
        </xsl:otherwise>
      </xsl:choose>
    </out:html>
  </xsl:template>
</xsl:transform>
Figure 5 The Same Transformation with Fallback
<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:out="http://www.w3.org/1999/xhtml"
  xmlns:ext="http://example.org/extension"
  extension-element-prefixes="ext"
>
  <xsl:template match="/">
    <out:html>
      <ext:doSomeFunkyMagic>
        <xsl:fallback>
          <!-- backup functionality goes here -->
          •••
        </xsl:fallback>
      </ext:doSomeFunkyMagic>
    </out:html>
  </xsl:template>
</xsl:transform>
Figure 6 Using Multiple msxsl:script Elements
<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:ms="urn:schemas-microsoft-com:xslt" 
  xmlns:js="urn:the-xml-files:xslt-js"
  xmlns:vb="urn:the-xml-files:xslt-vb">
  <xsl:output method="text"/>
  <ms:script language="JScript" implements-prefix="js">
    <![CDATA[
    function SayHelloFromJScript(name) {
       return "Hello from JScript:" + name;
    }
    ]]>
  </ms:script>
  <ms:script language="VBScript" implements-prefix="vb">
    <![CDATA[
    function SayHelloFromVBScript(name)
      SayHelloFromVBScript = "Hello from VBScript:" & name
    end function
    ]]>
  </ms:script>
  <xsl:template match="/">
    <!-- root template -->
    <xsl:value-of select="js:SayHelloFromJScript('billy')"/>
    <xsl:value-of select="vb:SayHelloFromVBScript('bob')"/>
  </xsl:template>
</xsl:transform>
Figure 7 XPath/MSXML Type Mapping for Function

W3C XPath Type
Equivalent JScript/VBScript Type
String
String.
Boolean
Boolean.
Number
Number.
Result Tree Fragment
IXMLDOMNodeList that contains a single node of type NODE_DOCUMENT_ FRAGMENT.
Node Set
IXMLDOMNodeList.
Figure 8 Extension Function
<ms:script language="JScript" implements-prefix="math">
  <![CDATA[
  function CalcDistance(points) {
    var xdelta = 
      parseFloat(points[0].selectSingleNode("x").text) - 
      parseFloat(points[1].selectSingleNode("x").text);
    var ydelta = 
      parseFloat(points[0].selectSingleNode("y").text) - 
      parseFloat(points[1].selectSingleNode("y").text);
    return Math.sqrt(Math.pow(xdelta, 2) +
                     Math.pow(ydelta, 2));
  }
  ]]>
</ms:script>
Figure 9 Process Result Tree Fragment
<ms:script language="JScript" implements-prefix="math">
  <![CDATA[
  function CalcDistance(points) {
    var x1 = 
       points[0].childNodes[0].selectSingleNode("x").text;
    var x2 = 
       points[0].childNodes[1].selectSingleNode("x").text;
    var y1 = 
       points[0].childNodes[0].selectSingleNode("y").text;
    var y2 = 
       points[0].childNodes[1].selectSingleNode("y").text;
    var xdelta = parseFloat(x1) - parseFloat(x2);
    var ydelta = parseFloat(y1) - parseFloat(y2);
    return Math.sqrt(Math.pow(xdelta, 2) + 
                     Math.pow(ydelta, 2));
  }
  ]]>
</ms:script>
Figure 10 XPath/MSXML Type Mapping for Return Values

JScript/VBScript Type
Equivalent W3C XPath Type
Number
Number
All other primitive types (String, Boolean, and so on)
String
Objects
Error
Figure 11 XPath/.NET Type System Mapping

W3C XPath Type
Equivalent .NET Class (Type)
String
System.String
Boolean
System.Boolean
Number
System.Double
Result Tree Fragment
System.Xml.XPath.XPathNavigator
Node Set
System.Xml.XPath.XPathNodeIterator
Figure 12 .NET Namespaces Available in msxsl:script

Namespace
Description
System
System class
System.Collection
Collection classes
System.Text
Text classes
System.Xml
Core XML classes
System.Xml.Xsl
XSLT classes
System.Xml.XPath
XPath classes
Figure 13 Calling from XPath
<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:ms="urn:schemas-microsoft-com:xslt" 
  xmlns:js="urn:the-xml-files:xslt-csharp"
>
  <ms:script language="JScript" implements-prefix="js">
    <![CDATA[
    void function1() {
       // omitted for brevity
    }
    void function2() {
       // omitted for brevity
    }
    •••
    ]]>
  </ms:script>
</xsl:transform>
Figure 14 Using a Person Object as an XSLT Extension
Dim xsldoc As New Msxml2.FreeThreadedDOMDocument40
Dim xmldoc As New Msxml2.FreeThreadedDOMDocument40
Dim xsltemp As New Msxml2.XSLTemplate40
Dim xslproc As Msxml2.IXSLProcessor
Dim p as New Person
p.name = "Michael"
p.age = 3
xsldoc.Load "person.xsl"
Set xsltemp.stylesheet = xsldoc.documentElement
Set xslproc = xsltemp.createProcessor
xmldoc.Load "input.xml"
xslproc.input = xmldoc
xslproc.addObject p, "urn:person"
xslproc.Transform
MsgBox xslproc.output