Microsoft XSLT

1. MXSML article
2. Installing the Microsoft XSLT processor
3. MSXML FAQ
4. Handling Entities in MSXML
5. Namespace URI for the MS node-set extension function
6. Microsoft XSLT command-line tool
7. ie5 default stylesheet
8. msxml default stylesheet - now in XSLT
9. Microsoft products

1.

MXSML article

Stuart Celarier

I've recently published an article titled "XSLT in MSXML" on PerfectXML at perfectxml.com

The article answers several frequently asked questions from XSL-List related to MSXML. In particular, it addresses the WD-xsl issue, how it came to be, why WD-xsl should be avoided, and how to use MSXML's XSLT 1.0 conformant processor in a variety of languages and settings. The abstract is provided below. Feedback is always welcome. Enjoy.

2.

Installing the Microsoft XSLT processor

Mike Brown

Dated July 2000. Will become outdated!

When you installed 3.0, it installed alongside 2.0, not replacing it, so that you could use one or the other. IE is unaware of the existence of 3.0. Look in your Windows system32 directory. You will see things like:

MSXML.DLL -- this is MSXML 2.0, although the DLL reports v5.00.2919.6303
msxml2.dll -- this is MSXML 2.5, although the DLL reports v7.50.4920.0
msxml3.dll -- this is MSXML 3.0, although the DLL reports v8.00.7309.1

To tell IE5 that you want it to use MSXML 3.0, run 'xmlinst.exe', which is also in the system32 directory. Just run it once. It will make whatever changes are necessary to make 3.0 the default for IE.

If you are not using IE and are accessing the components directly, make sure you are accessing the right ones.

I also referred in my message to the microsoft site

By the way, if you use a command line and call XMLINST using:

 "xmlinst -?"

It will show some help text. "Replace" mode is when you use no arguments, I presume.

David Schach adds If msxml.dll is registered on the machine then regsvr32 msxml3.dll will install msxml3 in side by side mode. In side by side mode IE will not use msxml3. If msxml.dll is not registered then regsvr32 msxml3.dll will install msxml3.dll in replace mode. There are at least two ways to remove msxml.dll

regsvr32 msxml.dll /u

or

xmlinst /u

Alternatively, xmlinst msxml3.dll should do both of the above steps and register msxml3.dll in replace mode.

3.

MSXML FAQ

Joshua Allen

I also am aware that it gets frustrating to answer questions about MSXML all the time, so I put up a page at MXSL FAQ. The page is really just meant to be a guide for people with MSXML about approaching xslt-list; how to troubleshoot, what problems are common, etc. before coming to the list with questions. I'm quite happy to modify it if anyone has suggestions.. Replying with this URL could be an easy way to answer people who come to the list asking questions because they are stuck in IE5 XSL Working-draft hell. Any comments, etc. are appreciated.

4.

Handling Entities in MSXML

Mike Brown

> <body>Some text &dllr; </body>
> 
> I get...
> 
> <body>Some text &amp;dllr</body>
> 
> What I want is:
> <body>Some text &dllr;</body>

You mentioned you don't have a DTD. Your question boils down to "I'm referring to entities that haven't been declared. Why aren't they working?"

The only entity references you can have in an XML document of any kind, including XSL documents, without a DTD that declares the entities, are the ones that are built-in to XML:

  &amp;
  &lt;
  &gt;
  &apos;
  &quot;

These are needed so that you can differentiate markup from character data. I suspect that MSXML is being lenient when it allows you to have a reference to an undeclared entity in your source XML/XHTML, or perhaps you're just not using the method properly. In either case, rather than complain about your undeclared entity, it's pretending that the reference is really just character data, as if you had said

<body><![CDATA[Some text &dllr; ]]></body>

You must realize that entities are numerous physical storage units which all together comprise the singular logical document. It is this single logical document that you are concerned with in XSL. You feed the XSL processor the document entity (the primary entity for the document), and it hands it off to an XML parser, which abstracts away all of the 'physical' aspects of it -- so things like general parsed entity references go away, replaced by their replacement text, and the bytes<->character encodings for each entity also go away. The parser reports on the single logical hierarchy of elements, attributes, and character data that it finds, and the XSL processor makes use of that information to create an internal representation of the XPath/XSLT node tree. This node tree has no concept of entities and entity references.

If you are thinking "I want &foo; in the output" then you have to either fake it by creating a text node with the characters & f o o ; and the disable-output-escaping attribute set to "yes", or your have to rely on your XSL processor's output method to know that certain characters or node types should be emitted entity references. This is the kind of thing that the HTML output method does in the XSL processors that support it -- certain markup characters, and most text node characters not in the ASCII range (0x0..0x7E) are emitted as numeric character references like &#1234; or as SGML entity references like &bull;.

Even though you are managing to somehow get references to undeclared entities parsed as just the characters that make up the entity reference, at that point it is just character data and "&" is no longer special, so it *has* to be escaped on output, to preserve its status as character data rather than markup. Your only workaround is if your XSL processor supports the disable-output-escaping option that was introduced in the later working drafts of XSLT 1.0, you can do something like:

<xsl:template match="body">
  <body>
    <xsl:value-of select="." disable-output-escaping="yes"/>
  </body>
</xsl:tempalte>

5.

Namespace URI for the MS node-set extension function

Julian Reschke

Should be xmlns:msxsl="urn:schemas-microsoft-com:xslt".

6.

Microsoft XSLT command-line tool

Andrew Kimball

A command-line wrapper (source + binary) for Microsoft's XSLT processor can be found at the microsoft site

Under XSL, click "MSXSL.EXE Command Line Transformation Utility". MSXSL.EXE requires that MSXML.DLL be installed on the machine.

7.

ie5 default stylesheet

Mike Brown



> do you know how i can access or refer to the ie5 default xsl stylesheet ?
> ( the one formatting xml files as a tree ? )

From the MSXML FAQ at www.netcrucible.com...

19. How does Internet Explorer format XML files in a collapsible view, and how can I modify this behavior?

For XML files that do not have a stylesheet associated, Microsoft Internet Explorer uses a default XSL stylesheet to create a DHTML rendering of the XML file. Depending on which version of MSXML you are using, you can browse to either res://msxml3.dll/DEFAULTSS.xsl or res://msxml.dll/DEFAULTSS.xsl. The res:// URN format indicates that the XSL file is compiled as a resource directly into the dll. If you have a binary resource editor (such as the one included with Visual C++), you can edit the XSL directly inside the MSXML dll and save back into the binary file. Alternately, you can start with a copy of the stylesheet from http://msdn.microsoft.com/xml/samples/defaultss/defaultss.xsl.

8.

msxml default stylesheet - now in XSLT

Nate Austin

Alright, I did the conversion. Chances are, there are still some errors in what I did as I tossed it out quickly. If you see any, be sure to let me know. This is a nice display, and should work in any dhtml-aware window. If you'd like to use it for other applications, that is up to Jonathan Marsh, I suppose, since he wrote the original. Enjoy!

defaultss.xslt follows:

<?xml version="1.0"?>
<!--
  IE5 default style sheet, provides a view of any XML document
  and provides the following features:
  - auto-indenting of the display, expanding of entity references
  - click or tab/return to expand/collapse
  - color coding of markup
  - color coding of recognized namespaces - xml, xmlns, xsl, dt
  
  This style sheet is available in IE5 in a compact form at the URL
  "res://msxml.dll/DEFAULTSS.xsl".  This version differs only in the
  addition of comments and whitespace for readability.
  
  Author:  Jonathan Marsh (jmarsh@microsoft.com)
  Modified:   05/21/2001 by Nate Austin (naustin@idsgrp.com)
                         Converted to use XSLT rather than WD-xsl
-->

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:dt="urn:schemas-microsoft-com:datatypes"
                xmlns:d2="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882">

<xsl:template match="/">
  <HTML>
    <HEAD>
      <STYLE>
        BODY {font:x-small 'Verdana'; margin-right:1.5em}
      <!-- container for expanding/collapsing content -->
        .c  {cursor:hand}
      <!-- button - contains +/-/nbsp -->
        .b  {color:red; font-family:'Courier New'; font-weight:bold;
	  text-decoration:none}
      <!-- element container -->
        .e  {margin-left:1em; text-indent:-1em; margin-right:1em}
      <!-- comment or cdata -->
        .k  {margin-left:1em; text-indent:-1em; margin-right:1em}
      <!-- tag -->
        .t  {color:#990000}
      <!-- tag in xsl namespace -->
        .xt {color:#990099}
      <!-- attribute in xml or xmlns namespace -->
        .ns {color:red}
      <!-- attribute in dt namespace -->
        .dt {color:green}
      <!-- markup characters -->
        .m  {color:blue}
      <!-- text node -->
        .tx {font-weight:bold}
      <!-- multi-line (block) cdata -->
        .db {text-indent:0px; margin-left:1em; margin-top:0px;
	  margin-bottom:0px;
             padding-left:.3em; border-left:1px solid #CCCCCC; font:small
	  Courier}
      <!-- single-line (inline) cdata -->
        .di {font:small Courier}
      <!-- DOCTYPE declaration -->
        .d  {color:blue}
      <!-- pi -->
        .pi {color:blue}
      <!-- multi-line (block) comment -->
        .cb {text-indent:0px; margin-left:1em; margin-top:0px;
	  margin-bottom:0px;
             padding-left:.3em; font:small Courier; color:#888888}
      <!-- single-line (inline) comment -->
        .ci {font:small Courier; color:#888888}
        PRE {margin:0px; display:inline}
      </STYLE>

      <SCRIPT><xsl:comment><![CDATA[
        // Detect and switch the display of CDATA and comments from an
	  inline view
        //  to a block view if the comment or CDATA is multi-line.
        function f(e)
        {
          // if this element is an inline comment, and contains more than a
	  single
          //  line, turn it into a block comment.
          if (e.className == "ci") {
            if (e.children(0).innerText.indexOf("\n") > 0)
              fix(e, "cb");
          }
          
          // if this element is an inline cdata, and contains more than a
	  single
          //  line, turn it into a block cdata.
          if (e.className == "di") {
            if (e.children(0).innerText.indexOf("\n") > 0)
              fix(e, "db");
          }
          
          // remove the id since we only used it for cleanup
          e.id = "";
        }
        
        // Fix up the element as a "block" display and enable
	  expand/collapse on it
        function fix(e, cl)
        {
          // change the class name and display value
          e.className = cl;
          e.style.display = "block";
          
          // mark the comment or cdata display as a expandable container
          j = e.parentElement.children(0);
          j.className = "c";

          // find the +/- symbol and make it visible - the dummy link
	  enables tabbing
          k = j.children(0);
          k.style.visibility = "visible";
          k.href = "#";
        }

        // Change the +/- symbol and hide the children.  This function works
	  on "element"
        //  displays
        function ch(e)
        {
          // find the +/- symbol
          mark = e.children(0).children(0);
          
          // if it is already collapsed, expand it by showing the children
          if (mark.innerText == "+")
          {
            mark.innerText = "-";
            for (var i = 1; i < e.children.length; i++)
              e.children(i).style.display = "block";
          }
          
          // if it is expanded, collapse it by hiding the children
          else if (mark.innerText == "-")
          {
            mark.innerText = "+";
            for (var i = 1; i < e.children.length; i++)
              e.children(i).style.display="none";
          }
        }
        
        // Change the +/- symbol and hide the children.  This function work
	  on "comment"
        //  and "cdata" displays
        function ch2(e)
        {
          // find the +/- symbol, and the "PRE" element that contains the
	  content
          mark = e.children(0).children(0);
          contents = e.children(1);
          
          // if it is already collapsed, expand it by showing the children
          if (mark.innerText == "+")
          {
            mark.innerText = "-";
            // restore the correct "block"/"inline" display type to the PRE
            if (contents.className == "db" || contents.className == "cb")
              contents.style.display = "block";
            else contents.style.display = "inline";
          }
          
          // if it is expanded, collapse it by hiding the children
          else if (mark.innerText == "-")
          {
            mark.innerText = "+";
            contents.style.display = "none";
          }
        }
        
        // Handle a mouse click
        function cl()
        {
          e = window.event.srcElement;
          
          // make sure we are handling clicks upon expandable container
	  elements
          if (e.className != "c")
          {
            e = e.parentElement;
            if (e.className != "c")
            {
              return;
            }
          }
          e = e.parentElement;
          
          // call the correct funtion to change the collapse/expand state
	  and display
          if (e.className == "e")
            ch(e);
          if (e.className == "k")
            ch2(e);
        }

        // Dummy function for expand/collapse link navigation - trap onclick
	  events instead
        function ex() 
        {}

        // Erase bogus link info from the status window
        function h()
        {
          window.status=" ";
        }

        // Set the onclick handler
        document.onclick = cl;
        
      ]]></xsl:comment></SCRIPT>
    </HEAD>

    <BODY class="st"><xsl:apply-templates/></BODY>

  </HTML>
</xsl:template>

<!-- Templates for each node type follows.  The output of
each template has a similar structure to enable script to
walk the result tree easily for handling user
interaction. -->
  
<!-- Template for the DOCTYPE declaration.  No way to get
	  the DOCTYPE, so we just put in a placeholder -->

<!--  no support for doctypes
<xsl:template match="node()[nodeType()=10]">
  <DIV class="e"><SPAN>
  <SPAN class="b">&#160;</SPAN>
  <SPAN class="d">&lt;!DOCTYPE <xsl:value-of 
	  select="name()"/><I> (View
Source for full doctype...)</I>&gt;</SPAN>
  </SPAN></DIV>
</xsl:template>
-->

<!-- Template for pis not handled elsewhere -->
<xsl:template match="processing-instruction()">
  <DIV class="e">
  <SPAN class="b">&#160;</SPAN>
  <SPAN class="m">&lt;?</SPAN><SPAN class="pi"><xsl:value-of
select="name()"/>&#160;<xsl:value-of select="."/></SPAN><SPAN
class="m">?&gt;</SPAN>
  </DIV>
</xsl:template>

<!-- Template for the XML declaration.  Need a separate template because the
pseudo-attributes
    are actually exposed as attributes instead of just element content, as
in other pis -->
<!--  No support for the xml declaration
<xsl:template match="pi('xml')">
  <DIV class="e">
  <SPAN class="b">&#160;</SPAN>
  <SPAN class="m">&lt;?</SPAN><SPAN class="pi">xml 
	  <xsl:for-each
select="@*"><xsl:value-of select="name()"/>="<xsl:value-of select="."/>"
</xsl:for-each></SPAN><SPAN class="m">?&gt;</SPAN>
  </DIV>
</xsl:template>
-->

<!-- Template for attributes not handled elsewhere -->
<xsl:template match="@*" xml:space="preserve"><SPAN><xsl:attribute
name="class"><xsl:if
test="starts-with(name(),'xsl:')">x</xsl:if>t</xsl:attribute> 
	  <xsl:value-of
select="name()" /></SPAN><SPAN class="m">="</SPAN>
	  <B><xsl:value-of
select="."/></B><SPAN class="m">"</SPAN></xsl:template>

<!-- Template for attributes in the xmlns or xml namespace -->
<!--  UNKNOWN
<xsl:template match="@xmlns:*|@xmlns|@xml:*"><SPAN 
	  class="ns"> <xsl:value-of
select="name()"/></SPAN><SPAN class="m">="</SPAN>
	  <B class="ns"><xsl:value-of
select="."/></B><SPAN class="m">"</SPAN></xsl:template>
-->

<!-- Template for attributes in the dt namespace -->
<!-- UNKNOWN
<xsl:template match="@dt:*|@d2:*"><SPAN 
	  class="dt"> <xsl:value-of
select="name()"/></SPAN><SPAN class="m">="</SPAN><B 
	  class="dt"><xsl:value-of
select="."/></B><SPAN class="m">"</SPAN></xsl:template>
-->

<!-- Template for text nodes -->
<xsl:template match="text()">
  <DIV class="e">
  <SPAN class="b">&#160;</SPAN>
  <SPAN class="tx"><xsl:value-of select="."/></SPAN>
  </DIV>
</xsl:template>


<!-- Note that in the following templates for comments
and cdata, by default we apply a style appropriate for
single line content (e.g. non-expandable, single line
display).  But we also inject the attribute 'id="clean"' and
a script call 'f(clean)'.  As the output is read by the
browser, it executes the function immediately.  The function
checks to see if the comment or cdata has multi-line data,
in which case it changes the style to a expandable,
multi-line display.  Performing this switch in the DHTML
instead of from script in the XSL increases the performance
of the style sheet, especially in the browser's asynchronous
case -->
  
<!-- Template for comment nodes -->
<xsl:template match="comment()">
  <DIV class="k">
  <SPAN><A class="b" onclick="return false" onfocus="h()"
STYLE="visibility:hidden">-</A> <SPAN class="m">
	  &lt;!--</SPAN></SPAN>
  <SPAN id="clean" class="ci"><PRE>
	  <xsl:value-of select="."/></PRE></SPAN>
  <SPAN class="b">&#160;</SPAN> <SPAN 
	  class="m">--&gt;</SPAN>
  <SCRIPT>f(clean);</SCRIPT></DIV>
</xsl:template>

<!-- Template for cdata nodes -->
<!-- UNSUPPORTED
<xsl:template match="cdata()">
  <DIV class="k">
  <SPAN><A class="b" onclick="return false" onfocus="h()"
STYLE="visibility:hidden">-</A> <SPAN class="m">
	  &lt;![CDATA[</SPAN></SPAN>
  <SPAN id="clean" class="di"><PRE><xsl:value-of 
	  select="."/></PRE></SPAN>
  <SPAN class="b">&#160;</SPAN> <SPAN 
	  class="m">]]&gt;</SPAN>
  <SCRIPT>f(clean);</SCRIPT></DIV>
</xsl:template>
-->


<!-- Note the following templates for elements may
examine children.  This harms to some extent the ability to
process a document asynchronously - we can't process an
element until we have read and examined at least some of its
children.  Specifically, the first element child must be
read before any template can be chosen.  And any element
that does not have element children must be read completely
before the correct template can be chosen. This seems an
acceptable performance loss in the light of the formatting
possibilities available when examining children. -->

<!-- Template for elements not handled elsewhere (leaf nodes) -->
<xsl:template match="*">
  <DIV class="e"><DIV STYLE="margin-left:1em;text-indent:-2em">
  <SPAN class="b">&#160;</SPAN>
  <SPAN class="m">&lt;</SPAN><SPAN><xsl:attribute 
	  name="class"><xsl:if
test="starts-with(name(),'xsl:')">x</xsl:if>t</xsl:attribute>
	  <xsl:value-of
select="name()"/></SPAN> <xsl:apply-templates 
	  select="@*"/><SPAN class="m">
/&gt;</SPAN>
  </DIV></DIV>
</xsl:template>
  
<!-- Template for elements with comment, pi and/or cdata children -->
<xsl:template match="*[comment() | processing-instruction()]">
  <DIV class="e">
  <DIV class="c"><A href="#" onclick="return false" onfocus="h()"
class="b">-</A> <SPAN 
	  class="m">&lt;</SPAN><SPAN><xsl:attribute
name="class"><xsl:if
test="starts-with(name(),'xsl:')">x</xsl:if>t</xsl:attribute>
	  <xsl:value-of
select="name()"/></SPAN><xsl:apply-templates select="@*"/> 
	  <SPAN
class="m">&gt;</SPAN></DIV>
  <DIV><xsl:apply-templates/>
  <DIV><SPAN class="b">&#160;</SPAN> <SPAN
class="m">&lt;/</SPAN><SPAN><xsl:attribute name="class">
	  <xsl:if
test="starts-with(name(),'xsl:')">x</xsl:if>t</xsl:attribute>
	  <xsl:value-of
select="name()"/></SPAN><SPAN class="m">&gt;</SPAN></DIV>
  </DIV></DIV>
</xsl:template>

<!-- Template for elements with only text children -->
<xsl:template match="*[text() and not(comment() |
processing-instruction())]">
  <DIV class="e"><DIV STYLE="margin-left:1em;text-indent:-2em">
  <SPAN class="b">&#160;</SPAN> <SPAN
class="m">&lt;</SPAN><SPAN><xsl:attribute 
	  name="class"><xsl:if
test="starts-with(name(),'xsl:')">x</xsl:if>t</xsl:attribute>
	  <xsl:value-of
select="name()"/></SPAN><xsl:apply-templates select="@*"/>
  <SPAN class="m">&gt;</SPAN><SPAN class="tx">
	  <xsl:value-of
select="."/></SPAN><SPAN class="m">&lt;/</SPAN>
	  <SPAN><xsl:attribute
name="class"><xsl:if
test="starts-with(name(),'xsl:')">x</xsl:if>t</xsl:attribute>
	  <xsl:value-of
select="name()"/></SPAN><SPAN class="m">&gt;</SPAN>
  </DIV></DIV>
</xsl:template>

<!-- Template for elements with element children -->
<xsl:template match="*[*]">
  <DIV class="e">
  <DIV class="c" STYLE="margin-left:1em;text-indent:-2em"><A href="#"
onclick="return false" onfocus="h()" class="b">-</A> <SPAN
class="m">&lt;</SPAN><SPAN>
	  <xsl:attribute name="class"><xsl:if
test="starts-with(name(),'xsl:')">x</xsl:if>t</xsl:attribute>
	  <xsl:value-of
select="name()"/></SPAN><xsl:apply-templates select="@*"/> <SPAN
class="m">&gt;</SPAN></DIV>
  <DIV><xsl:apply-templates/>
  <DIV><SPAN class="b">&#160;</SPAN> <SPAN
class="m">&lt;/</SPAN><SPAN><xsl:attribute 
	  name="class"><xsl:if
	  test="starts-with(name(),'xsl:')">x</xsl:if>
t</xsl:attribute><xsl:value-of
select="name()"/></SPAN><SPAN class="m">&gt;</SPAN></DIV>
  </DIV></DIV>
</xsl:template>

</xsl:stylesheet>



9.

Microsoft products

Mike Brown


> Yes, reading 2 Wrox books telling me it was msxMl and then, in a state
> of tiredness (way too much stress at work) somehow gliding over your
> comments that it was msxSl, I tried it.  Yes, it was ..S.. And not X.

Well, to be clear:

MSXML (msxml*.dll) is the library that provides the XML processing functionality, including parsing and XSLT processing. It can't be used on its own, but you can invoke its functions from within your own code, or from code that runs within Internet Explorer. IE5 and up come with some version of MSXML, which you can replace or supplement with newer versions.

MSXSL (msxsl.exe) is an executable program that you can obtain from the MSDN

site. It allows you to invoke MSXML's XSLT processing routines from the command line. It doesn't provide the routines itself; it just wraps / provides an interface to the ones that are relevant to XSL.

So, the WROX books might not be in the wrong. They may be assuming you are invoking MSXML via your own programs or via VBScript or JavaScript within an HTML document loaded by Internet Explorer.