perfectxml.com
 Basic Search  Advanced Search   
Topics Resources Free Library Software XML News About Us
  You are here: home »» Info Bank »» Articles » XSLT in MSXML Saturday, 23 February 2008
 

Back to Articles Page      

        


XSLT in MSXML

Go to Page: 1 | 2  

Author: Stuart Celarier, Fern Creek Corporation

Stuart Celarier is a software consultant and instructor in Portland, Oregon, focusing on .NET, XML, Web Services, COM, C++ and C#. You can reach Stuart at or through his web site www.ferncrk.com.

Copyright © 2002, Stuart Celarier, Fern Creek Corporation. All rights reserved.


Article Date: May 2002
Abstract: Microsoft introduced full XSLT 1.0 support in MSXML 3.0. However, earlier versions of MSXML are not XSLT 1.0 conformant (far from it) but instead support an early draft of XSLT known as WD-xsl. Even if you have the most recent MSXML 4.0 version installed, you may get a nonconforming version of XSLT by default. It all depends on both what versions of MSXML you have installed and how they are configured. This article explains this situation and how to utilize the XSLT 1.0 conformant processor in MSXML. It also examines the advanced classes that make XSLT efficient to use in ASP applications and middle tier technology.
Audience: This article assumes that you are familiar with XSLT, HTML and JavaScript. Visual Basic, C++ and COM are briefly used in a few examples.
Source code: The source code accompanying this article can be downloaded from https://perfectxml.com/downloads/XsltInMsxml.zip.
Demo: Click here to see the demo (requires MSXML 4.0 on the client side).

The state of XSLT in MSXML

In order to discuss how the MSXML relates to the XSLT specification, let's begin with a quick introduction to the development of specifications at the W3C.


Where to W3C specifications come from?

The World Wide Web Consortium (W3C) develops a majority of specifications that comprise the World Wide Web and make it increasingly more useful, including the specifications for HTML, XML, XSLT, and many more. The W3C uses an established process for creating specifications.


W3C specifications are initially published as Working Drafts which are, in the words of the W3C ,

...submitted for review by W3C Members and other interested parties. These are draft documents and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to use W3C working drafts as reference material or to cite them as other than “work in progress”.
After a successful Working Draft specification has received "significant technical review” within the W3C, it is promoted to a Candidate Recommendation which is a call for implementation and technical feedback from the public. Following that, a specification can become a Proposed Recommendation indicating that the W3C group that working on the specification have reached consensus and the W3C Director has proposed it for review by the W3C Advisory Committee.


Once review of the Proposed Recommendation is complete, the specification can finally become a W3C Recommendation. Again quoting the W3C, a Recommendation

...represents consensus within W3C and has the Director’s stamp of approval. W3C considers that the ideas or technology specified by a Recommendation are appropriate for widespread deployment and promote W3C's mission.
In essence, only a Recommendation is the final specification, everything else is a work in progress.


WD-xsl and XSLT 1.0 conformant processors

Now we can understand a very important point. The XSLT technology in MSXML prior to MSXML 3.0 is based on one of the Working Draft versions of the XSLT 1.0 specification. MSXML 3.0 was the first release to have an XSLT conformant processor based on the XSLT 1.0 Recommendation. MSXML 4.0 further improves in that regard and contineous to provide 100% XSLT 1.0 conformant processor.


The XSLT technology is so compelling that Microsoft chose to become an early adopter of it, releasing it to developers even while XSLT was still changing. And XSLT changed a lot before it final XSLT 1.0 Recommendation was published.


It is easy to identify XSLT stylesheets written to the XSLT 1.0 Recommendation, as they use XML elements in the namespace http://www.w3.org/1999/XSL/Transform. The document (or root) element of an XSLT 1.0 stylesheet is generally written like this:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"/>


On the other hand, Microsoft's XSLT processors prior to MSXML 4.0 use a different XML namespace for their elements, so that the document element of an XSLT stylesheet based on an XSLT Working Draft is written like this:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"/>
For this reason, this is often called the WD-xsl version or Working Draft version of XSLT.


It needs to be emphasized that WD-xsl is not XSLT 1.0, not even close. The XSLT specification, as well as the XPath specification on which it depends, changed a lot between the version of the Working Draft that Microsoft used for WS-xsl and the final Recommendation. WD-xsl and XSLT 1.0 must be considered completely separate languages, and I strongly advise you to consider WD-xsl as a temporary solution which is now obsolete.


MSXML 3.0 has support for both the XSLT 1.0 recommendation and WD-xsl. It selects which technology to use depending on the namespace used for the XSLT elements. With MSXML 4.0 Microsoft dropped support for WD-xsl. If you try to use the WD-xsl (http://www.w3.org/TR/WD-xsl) with MSXML 4.0 XSLT processor, you'll get an error -2147467259 The "http://www.w3.org/TR/WD-xsl" namespace is no longer supported in this version of MSXML. In case you have previously developed WD-xsl stylesheets, your friends in Redmond have provided an conversion utility called XSL to XSLT Converter 1.1 which is available for download from the MSDN web site.


The devil is in the details

That doesn’t seem so bad, we can all just use the XSLT 1.0 conformant processor from MSXML 3.0 or 4.0 and code happily ever after, right? Well, it is a little more complicated than that. A good deal depends on which versions of MSXML are installed and how they are configured.


In releases of MSXML prior to MSXML 4.0 you had a option to install MSXML in side-by-side or replace mode (via the XmlInst.exe utility). Installing a version of MSXML in replace mode involved configuration in the registry making that version be the default one for XML services. However it is not possible to install MSXML 4.0 to be the default XML technology, there is no replacement mode install any more.


What this means is that the only way you can make a XSLT 1.0 conformant processor be the default processor used by Windows is to have MSXML 3.0 installed in replacement mode. Otherwise, even if you have MSXML 4.0 installed, by default you will get a WD-xsl processor. And we just learned that WD-xsl is not XSLT 1.0.


In a moment we’ll look at what the term 'default' really means and how to invoke the specific version of the XSLT processor that we want. But first let’s figure out what versions of MSXML are installed on your system.


Microsoft provides MSXML as a free downloadable component (see http://msdn.microsoft.com/xml), and it also is included with recent versions of Internet Explorer. Specifically, IE 5.5 includes MSXML 2.0 and IE 6.0 includes MSXML 3.0. Separately, MSXML 2.6 was also available for download. Depending on what you’ve installed you may have one, two or all three of these versions of MSXML on your computer, and any one of them may be the default version.


(By the way, if you need technical information on different versions of MSXML, their filenames, file version numbers and tracking down what products they were included in, check the Notes section near the bottom of the MSXML 3.0 SP1 .cab File Redistribution Package article on the MSDN web site. This is the most complete information I've found, and it seems to correct a few slight misstatements elsewhere in the Microsoft literature.)


If you want to find out which versions of MSXML are installed on your system, fire up the RegEdit utility and navigate to the HKEY_CLASSES_ROOT\Msxml2.DOMDocument entry. Mxsml2.DOMDocument is the version-independent name of the COM class for the XML DOM in MSXML. Just below that entry you should see one or more version-dependent COM class names such as Msxml2.DOMDocument.2.6 and so forth, a different one for each version of MSXML installed.



Figure 1. Registry keys for MSXML

From Figure 1 you can see that I have MSXML 2.6, 3.0 and 4.0 installed on my computer, and from the value of the Msxml2.DOMDocument\CurVer key you can tell that MSXML 3.0 is the default (version independent) one. When I drag an XML file and drop it on Internet Explorer on my system it is displayed using MSXML 3.0.


The fundamental reason why MSXML 4.0 cannot be made to be the default is that Microsoft removed the version independent GUIDs and PROGIDs in MSXML 4.0. If you would like more information about the reasons for this and the implications of it, consult the MSDN Library article XML Web Services / XML Core / MSXML / SDK Documentation / Microsoft XML Core Services (MSXML) 4.0 / GUID and ProgID Information.


Sidebar: default XSLT styling in Internet Explorer

By the way, when Internet Explorer displays an XML file, it is actually styling it with IE's default XSLT stylesheet. The default XSLT stylesheet transforms arbitrary XML into a Dynamic HTML (DHTML) document which provides fonts and colors and allows you to expand and collapse elements as shown in Figure 2.



Figure 2. Default transformation in Internet Explorer

This default stylesheet is a resource in the MSXML DLL which is identified by the URN res://msxml.dll/DEFAULTSS.xsl or res://msxml3.dll/DEFAULTSS.xsl. You can view that document in Internet Explorer, too, and with all the <xsl:template> elements collapsed it looks like Figure 3 (notice the WD-xsl namespace).



Figure 3. The defaultss.xsl stylesheet

If you are interested in this stylesheet, you probably want to obtain a copy that has been converted to XSLT 1.0. Steve Muench, coeditor for the W3C's requirements specifications for XSLT 2.0 and XPath 2.0, posted one to the XSL-List Forum and archived at http://www.biglist.com/lists/xsl-list/archives/200003/msg00769.html. This has been tested on a variety of other XSLT processors for compatibility.


You can visit the XSL-List Forum and subscribe to the mailing list at http://www.mulberrytech.com/xsl/xsl-list/. It is an incredible resource for both XSL and XSLT programming. One word of warning, if you ask a WD-xsl question there you will no doubt be advised to change to XSLT 1.0 technology. They've grown tired of saying it time and again. And, as always, please lurk before you leap.


Invoking the MSXML XSLT 1.0 processor

Now that we are thoroughly familiar with which versions of MSXML may be installed on a computer and why the nonconforming WD-xsl processor is used by default, let's turn our attention to using the XSLT 1.0 processor in MSXML 3.0 and 4.0.


If you have the option, you would probably prefer to use the MSXML 4.0 XSLT processor over the 3.0 version. From a performance standpoint, the XSLT processor in MSXML 4.0 clocks in at about four times faster than its predecessor, eight times faster in some scenarios. Additionally, since MSXML 4.0 dropped support for WD-xsl, making explicit use of MSXML 4.0 will help ferret out any obsolete WD-xsl stylesheets early in the development process.


With XSLT 1.0 processors available in both MSXML 3.0 and 4.0, for the rest of this article we'll talk about using the latest, greatest MSXML 4.0 unless otherwise stated. This will help simplify the discussion, and in most cases you will be able to see immediately how to work with MSXML 3.0 if you'd like.


Generally there are three ways to invoke an XSLT processor: using a distinguished XML processing instruction in the source document, from the command line, or programmatically using an API call. Let's examine each of these in turn and they can or can't be used to invoke MSXML 4.0's XSLT 1.0 processor.


The xml-stylesheet processing instruction

There is a short W3C Recommendation specification called Associating Style Sheets with XML Documents which defines an XML processing instruction (PI) that can be embedded in an XML document to indicate one or more stylesheets to use when displaying the document in a browser. The stylesheets could be cascading style sheets (CSS), XSLT stylesheets and potentially other types as well. Typical xml-stylesheet processing instructions look like this:


<?xml-stylesheet type="text/xsl" href="book.xsl"?>
<?xml-stylesheet type="text/css" href="ferncrk.css"?>

The first PI says to apply the XSLT stylesheet named book.xsl, and the second says to then apply the CSS stylesheet named ferncrk.css. While the PI allows the document to specify what stylesheet to apply, it does not allow it to specify which XSLT processor to use. As a result, Internet Explorer will use the default MSXML processor, which is a WD-xsl processor. Conclusion: we can't use the xml-stylesheet PI to invoke an XSLT 1.0 conformant processor.


In my opinion this is no great loss. Think about when you have two applications, a server that produces XML data and a client that consumes XML data, but the server and client use different data models. Historically we might have provided an Export As... feature in the server to produce client-compatible data, or an Import As... feature in the client so that it can consume server-produced data. Of course the problem with this approach is that it links the server and client software, so that a change in one (e.g., extending the data model) may require a corresponding change in the other. If we instead use XSLT to abstract the transformation process, that is a separate activity belonging to neither application, then the server and client remain uncoupled. Uncoupling the server and client is especially important when one server has multiple clients or visa versa.


But an xsl-stylesheet processing instruction embedded in the XML document implies that the server must know which client is consuming the data in order to select the correct stylesheet when it writes the data. From this perspective, the xsl-stylesheet processing instruction looks like it is explicitly linking server and client again, so it really is of limited use.


What's more, the XML crowd has been turning away from processing instructions (see Aaron Skonnard's XML Files column in the May 2002 issue MSDN Magazine, "Q: Are there any standard PIs in XML?") and the xsl-stylesheet is the only processing instruction that has been specified to date.


The msxsl command

The second way to invoke an XSLT processor is from the command line. The W3C specification does not specify a command line syntax, so it is left to each vendor to provide its own. In order to use the MSXML 4.0 processor from the command line you need to download and install the MSXSL.EXE Command Line Transformation Utility from MSDN Downloads. This is not included in the MSXML 4.0 download.


Running the msxsl -? command displays the command line syntax shown here.


c:\>msxsl -?
Microsoft (R) XSLT Processor Version 4.0

Usage: MSXSL source stylesheet [options] [param=value...] [xmlns:prefix=uri...]

Options:
    -?            Show this message
    -o filename   Write output to named file
    -m startMode  Start the transform in this mode
    -xw           Strip non-significant whitespace from source and stylesheet
    -xe           Do not resolve external definitions during parse phase
    -v            Validate documents during parse phase
    -t            Show load and transformation timings
    -pi           Get stylesheet URL from xml-stylesheet PI in source document
    -u version    Use a specific version of MSXML: '2.6', '3.0', '4.0'
    -             Dash used as source argument loads XML from stdin
    -             Dash used as stylesheet argument loads XSL from stdin
                        

Note that by default this command does not validate the source or stylesheet documents, use the -v flag when validation is required. The -m flag allows you to specify the starting mode for the transformation, this corresponds to the mode attributes on <xsl:template> and <xsl:apply-templates> elements in the stylesheet (see the section on modes in the XSLT specification for more information).


The msxsl command is handy for batch processing.  But you should be aware that on each invocation it must parse (and validate if specified) both the source document and the stylesheet. If you are performing many transformations using the same stylesheet, it will be advantageous to load the stylesheet once and apply it to several source XML documents. To get more control over the transformation process we look to programmatic invocation.


Invoking MSXML XSLT from JavaScript

In MSXML 4.0 the XSLT processor is exposed in the XML DOM object named Msxml2.DOMDocument.4.0. Here is a sample HTML file that uses JavaScript to load a source and stylesheet document and display the result in the body of the HTML page.


<html>
  <head>
    <title>Transform Sample</title>
    <script language="javascript">
      function init()
      {
        // load XML source document
        var source = new ActiveXObject("Msxml2.DOMDocument.4.0");
        source.async = false;
        source.load("record49a36bde.xml");

        // load XSLT stylesheet document
        var stylesheet = new ActiveXObject("Msxml2.DOMDocument.4.0");
        stylesheet.async = false;
        stylesheet.load("detail_view.xsl");

        // transform the source using the XSLT stylesheet
        target.innerHTML = source.transformNode(stylesheet);
      }
    </script>
  </head>

  <body onload="init()">
    <div id="target" />
  </body>
</html>

When this page gets loaded, the onload attribute of the <body> element calls the init function which is defined in the <script> block. The init function loads the source and stylesheet documents, performs the XSLT transformation, and sets the results as the HTML contained in the element identified with and id="target" attribute. That element is the <div> element that makes up the HTML body. Well, that much of what's going on is mostly Dynamic HTML (DHTML). You can learn more about DHTML from the MSDN Library under Web Development / HTML and Dynamic HTML.


Let's take a closer look at the script that loads the documents and performs the transformation.


The init function begins with a three step process to load the XML source document. First an XML DOM object is created. By using the version dependent name for the ActiveX object,  Msxml2.DOMDocument.4.0, we are specifying the MSXML 4.0 services and the cherished XSLT 1.0 compliant processor. Second, the asynch property of the XML DOM object is set to false, specifying that XML documents cannot be loaded into the DOM asynchronously. In our case, we require the entire document to be loaded before transformation can begin. Third, the source document is loaded into the XML DOM object by calling its load method.


This three step process is repeated to load the XSLT stylesheet into another XML DOM object. Then the transformNode method is called on the source XML DOM object, passing in the stylesheet XML DOM object as a parameter. The result is a string containing the serialized result of the transformation, and that string is set into the innerHTML property of the <div> element, causing the result to be displayed on the page.


Now that we understand how to do a simple transformation using JavaScript, let's examine performing XSLT transformations in other languages.


Invoking MSXML XSLT from Visual Basic

Here is a sample transformation written in Visual Basic.


Dim source As New Msxml2.DOMDocument4
Dim stylesheet As New Msxml2.DOMDocument40

' Load XML source document
source.async = False
source.Load "record49a36bde.xml"
 
' Load XSLT stylesheet document
stylesheet.async = False
stylesheet.Load "text_view.xsl"

' Perform transformation
MsgBox source.transformNode(stylesheet)

Notice that this code is also written against the XML DOM object, but here object is known by its Visual Basic class name: Msxsml2.DOMDocument40, not Msxml2.DOMDocument.4.0. Other than the name change, this code is very similar to the JavaScript example.


Invoking MSXML XSLT from C++

Here is an equivalent example written in C++. Aside from all the trappings of COM, this example is substantially the same as the JavaScript and Visual Basic examples.


#include "msxml2.h"

// ...
// Assume that COM is already initialized with CoInitialize(Ex)
// Error checking and handling elided for clarity

// load XML source document
IXMLDOMDocument40 * pSource;
::CoCreateInstance(CLSID_DOMDocument40, NULL, CLSCTX_INPROC_SERVER,
                   IID_IXMLDOMDocument40, (void**)&pSource);
pSource->put_async(VARIANT_FALSE);
pSource->load("record49a36bde.xml");

// load XSLT stylesheet document
IXMLDOMDocument40 * pStylesheet;
::CoCreateInstance(CLSID_DOMDocument40, NULL, CLSCTX_INPROC_SERVER,
                   IID_IXMLDOMDocument40, (void**)& pStylesheet);
pStylesheet->put_async(VARIANT_FALSE);
pStylesheet->load("text_view.xml");

// perform transformation
BSTR result;
pSource->transformNode(pStylesheet, &result);
::MessageBox(NULL, result, "Transform Result", MB_OK);

::SysFreeString(result);

Getting an XSLT result as a DOM

The astute reader may have noticed that there is something slightly amiss revealed by the previous C++ code example. The result of the transformation is a BSTR. Other than being a most foul and heinous data type (really, don't get me started), BSTR is, by definition, UTF-16 encoded. But MSXML 4.0 has built-in support for several different encodings including UTF-8, UTF-16, ISO-8859-1, and many others.


In order to fully support XML encoding, it is necessary to use the transformNodeToObject method of the XML DOM object. A call to transformNodeToObject takes two parameters: a stylesheet as an IXMLDOMNode, and a VARIANT containing an object to receive the output of the transformation. If the VARIANT is an XML DOM object, DOMDocument, then the transformation result is placed in the DOM. Alternatively, the output VARIANT can be an object with the IStream interface, in which case the transformation result is sent to the stream.


One of the benefits of outputting the transformation result as an XML DOM object is that the resulting output can be used directly as input for another transformation. Here is an scripting example that illustrates this kind of chaining.


Dim source As New Msxml2.DOMDocument4
        
// load XML source document
var source = new ActiveXObject("Msxml2.DOMDocument.4.0");
source.async = false;
source.load("record49a36bde.xml");
 
// load first XSLT stylesheet
var ssExtract = new ActiveXObject("Msxml2.DOMDocument.4.0");
ssExtract.async = false;
ssExtract.load("extractFromRecord.xsl");
 
// load second XSLT stylesheet
var ssFormat = new ActiveXObject("Msxml2.DOMDocument.4.0");
ssFormat.async = false;
ssFormat.load("format.xsl");
 
// create first resulting DOM document
var result1 = new ActiveXObject("Msxml2.DOMDocument.4.0");
result1.async = false;

// create second resulting DOM document
var result2 = new ActiveXObject("Msxml2.DOMDocument.4.0");
result2.async = false;

// perform two-stage transformation
source.transformNodeToObject(ssExtract, result1);
result1.transformNodeToObject(ssFormat, result2);

// do something interesting with result2...

Here we've got one stylesheet that extracts data from a record, and another stylesheet that formats extracted data. This factoring enables us to reuse one or the other or both stylesheets in other situations.


In this example the result of the first transformation was used as the source document for the second transformation. It is equally easy to handle the case where we are transforming XSLT stylesheets themselves, so that result of one transformation is used as the stylesheet for another transformation. Pretty cool.


Advanced XSLT performance and functionality

For performance reasons, implementers of XSLT processors usually architect their software so that it first compiles the stylesheet into an executable format, and then applies that to the source document. This is the case with the MSXML XSLT processor. However, when transformNode or transformNodeToObject is used, the stylesheet is compiled each time the method is called. That is simply inefficient and that overhead can be prohibitive in a middle tier or server application where performance is (almost) everything. That means that if you are developing something like an ASP application using XSLT, you'll want to become familiar with the XSLTemplate and XSLProcessor objects.


The XSLTemplate object provides a mechanism for caching a compiled stylesheet and then retrieving the compiled stylesheet as an XSLProcessor object for performing transformations. In addition, XSLProcessor also exposes other XSLT functionality that is not available anywhere else in the MSXML toolkit. Specifically, using an XSLProcessor object we can specify processing modes and pass parameters into a stylesheet. As an extensibility point, we can even also pass arbitrary COM objects into a stylesheet using an XSLProcessor object (see the section on extensions in the XSLT 1.0 specification).


The MSXML documentation in the MSDN Library is a bit of a muddle providing reference for XSLTemplate and XSLProcessor. It will help you to know that an XSLTemplate object is one that implements the IXSLTemplate interface, and similarly an XSLProcessor object is an object that implements the IXSLProcessor interface. You can find these interfaces documented in the MSDN Library section XML and Web Services / XML Core / XML General / SDK Documentation / Microsoft XML Core Services (MSXML) 4.0 / XML Reference / XML Helper Object/Interfaces.


More information can be gleaned from the examples in the MSDN Library and elsewhere. Some particularly useful examples are located in the MSDN Library article XML and Web Services / XML Core / XML General / SDK Documentation / XML (Extensible Markup Language) / XML and XSL Samples / XML Code Examples / Code Examples in Microsoft Jscript / XSLTemplate Examples. Please be aware that this article is from the MSXML 3.0 SDK, so the actual XSLT is WD-xsl, but the application of XSLTemplates is still relevant.


Let's dig in to a simple script example to acquaint ourselves with XSLTemplate and XSLProcessor.


<html>
  <head>
    <script language="javascript">
      var ss, cache;

      function init()
      {
        // create and load XSLT stylesheet – must be free-threaded
        ss = new ActiveXObject('MSXML2.FreeThreadedDOMDocument.4.0');
        ss.async = false;
        ss.load('stylesheet.xsl');

        // create XSLTemplate object and compile stylesheet into it
        cache = new ActiveXObject("Msxml2.XSLTemplate.4.0");
        cache.stylesheet = ss;
      }

      function transform(source)
      {
        // create and load source document
        var src = new ActiveXObject('MSXML2.DOMDocument.4.0');
        src.async = false;
        src.load(source);

        // retrieve cached XSLProcessor and transform the source document
        var proc = cache.createProcessor();
        proc.input = src;
        proc.transform();
        target.innerHTML = proc.output;
      }
    </script>
  </head>

  <body onload="init();">
    <div>
      Select a data set to transform: 
      <a href="javascript:transform('data1.xml')">data1.xml</a>
      <a href="javascript:transform('data2.xml')">data2.xml</a>
      <a href="javascript:transform('data3.xml')">data3.xml</a>
   </div>
   <div id="target">[Transformed data will appear here]</div>
  </body>
</html>

When the page is loaded the <body onload="init();"> tag directs the init function to be executed. The init function loads an XSLT stylesheet which follows the same familiar process with one exception: the object must be a FreeThreadedDOMDocument object rather than the DOMDocument we've used up to this point. The reason for this is that the IXSLProcessor interface is designed to handle asynchronous transformations. Next an XSLTemplate object is created and the stylesheet is set into the XSLTemplate's stylesheet property. This step compiles the stylesheet into its executable format for later use. Do note that setting the stylesheet property will fail unless the object being assigned is a free-threaded document object.


When a user clicks on one of the XML data files displayed in the first <div> element, the <a href="..."> link causes the transform function to be called with the XML filename as a parameter. The transform function loads the source XML file (using a regular DOMDocument object) and then gets a new XSLProcessor object by calling the XSLTemplate's createProcessor method. The XSLProcessor's input property is set to the XML source document, the transform method is called, and the result of the transform is retrieved from the output property and displayed in the <div id="target"> element.


Goto Page 2 (The Interactive Catalog example)

Go to Page: 1 | 2  

  

Back to Articles Page      

  Contact Us |  | Site Guide | About PerfectXML | Advertise ©2004 perfectxml.com. All rights reserved. | Privacy