Microsoft makes the MSXML 3.0 API available for free from its download site. Go to the following URL and search with the criteria "XML."
http://www.microsoft.com/downloads/search.asp
You have to specify your target operating system and "All Downloads." Then download the "MS XML Parser 3.0 Service Pack 1 release." This selection downloads a file called msxml3sp1.exe. Execute this file and follow the installation wizard to complete the installation.
Microsoft has released a preview version of the MSXML 4.0 API, but I have not had the chance to evaluate it. The example in this article uses version 3.0 and has been tested with the original release of the MSXML 3.0 API and with service pack 1.
If you like, you may download my XMLReports Browser utility, which handles the complete installation for you. If you do this, you get the MSXML3.0 API, which has been packaged with a simple browser utility that displays HTML in the MS Web Browser control.
XMLReports Browser Utility
The XMLReports Browser utility is a convenience tool that was developed to handle custom reporting in Visual Basic and ASP applications. The XMLReports Browser utility is a wrapper object that exposes the transformation feature of the Microsoft MSXML 3.0 API, and optionally displays the results in a simple browser. The user supplies the XML document and the XHTML/XSL template to the XMLReports Browser utility. The utility converts the documents to HTML.
Using this tool, the developer can modify the layout of reports by changing the text file that contains the EXtensible HTML (XHTML) and XSLT directives. The application does not need to be recompiled every time a report changes. Your reports are built using XHTML, so you can insert images, build tables, and populate them with the data in the XML document.
Many of the display characteristics of the browser are user-configurable. For example, the user may change the browser's caption, the browser's background colors, button images, button tool tips, and menu captions. Also, the browser object supports a WYSIWYG print function that prints all of the pages that have been inserted into the object by the client application. And you can submit multiple HTML pages to the browser object and page through them using the Next and Previous buttons.
Installing the XMLReports Browser Utility
The XMLReports Browser utility is packaged in a zip file that contains a self-extracting executable. Download the file, XMLReports.zip, at the following URL.
http://www.ftisystems.com/XMLReports.zip
Extract the files into a temporary directory. The XMLReports.zip file contains the following files.
- setup.exe - the setup program
- setup.lst - the packing list that is used by the setup program
- XMLReports.CAB - a cabinet file that contains the XMLReports object and its dependencies.
- XMLReports.doc - this document.
- Report.xml - a sample XML file.
- Report.xsl - a sample XHMTL file with XSLT directives.
Execute the setup.exe program and follow all of the directions to complete the installation. If the wizard asks you if you want to keep a newer version of a file on your system, do so. Do not overwrite newer versions of your files with those in the download.
Hardware and Software Requirements
The XMLReports Browser utility runs on Windows 95/98/NT/2000 machines. These machines must have Microsoft Internet Explorer 5.0 or higher, preferably 5.5.
On machines running Windows 95, OSR2 or higher is required. On machines running Windows NT, SP3 or higher is required.
XMLReports Browser Utility Usage
Create a new project in Visual Basic (VB). My example uses VB 6.0. Go to Project/References and select the "XMLReports" server. If it is not selected, click on the checkbox next to the name. If you are not using the XMLReports Browser utility, select the "Microsoft XML v3.0" server instead. The XMLReports server wraps the MSXML v3.0 Server, so you don't have to select it if you are using the XMLReports Browser utility.
The XMLReports Browser utility has two methods that convert XML to HTML. One method is called InitUsingStrings and the other is called InitUsingFiles. Client applications may call these methods repeatedly in order to generate multiple reports in the same browser object.
The InitUsingFiles function converts a client application's XML document to HTML. The caller specifies an XML document filename, an XSL template filename, and an HTML filename. The following function declaration describes the InitUsingFiles method in more detail. Public Function InitUsingFiles( strXMLFile As String, strXSLFile As String,strHTMLFile As String) As LongWherestrXMLFile a string that contains the full filespec to a file that contains the XML document.strXSLFile a string that contains the full filespec to a file that contains the XHTML and XSL directives. The template must conform to the XSLT namespace URI, http://www.w3.org/1999/XSL/Transform.strHTMLFile a string that contains the full filespec to a file that will contain the results of the transformation.Return Codes: 0 if no error occurs.<0 if an error occurs.
The InitUsingStrings method does the same thing as the InitUsingFiles method, except that the client application passes strings as parameters instead of filenames.
Using the XMLReports Browser Utility
The following code fragment illustrates how to use the XMLReports Browser utility in a Visual Basic application. Dim objXMLReports As XMLReports.XMLUtilitiesDim strHTMLFile As StringDim strXMLFile As StringDim strXSLFile As StringDim lngResults As Long' Make sure the Report.xml and Report.xsl files are in the App.Path directory.strHTMLFile = App.Path & "Report.html"strXMLFile = App.Path & "Report.xml"strXSLFile = App.Path & "Report.xsl"Set objXMLReports = New XMLReports.XMLUtilitieslngResults = objXMLReports.InitUsingFiles(strXMLFile, strXSLFile, strHTMLFile)If lngResults = 0 Then ' Display the results in the Web Browser Control. objXMLReports.ShowElse ' An error occurred. See the documentation that comes with the ' XMLReports distribution for a list of the valid values that can be returned.End If
First, create an instance of the XMLReports object. Then specify the three filenames that have to be passed to the InitUsingFiles method. If the InitUsingFiles method returns zero, no error has occurred. Our example shows the browser object. A non-zero return code means that an error occurred. You will receive an error code when a file is not found by the method, when the XSL template has invalid directives in it, and when the XML data is not well-formed.
If the XML data is well-formed, but the XSL template has an invalid directive, the XMLReports object creates an HTML result that shows the exact location where the error occurred in the XSL template. This handy little feature makes it easier to debug your XSL templates during the design phase. A following section will show you how to locate the source of the error in an XSL template.
The XMLReports Browser Utility has a large number of properties and methods, most of which configure the look and feel of the browser object. See the documentation that comes with the XMLReports Browser utility for more details about these properties and methods, and for a list of error codes.
Client applications do not have to display the browser object. Instead, they can execute the InitUsingStrings method to return the results of the transformation in a string. These results can be rendered with dynamic HTML in a client browser, or with Active Server Pages (ASP) scripting logic at the server. If you are going to transform XML in an Active Server Page, you probably want to use the MSXML 3.0 API directly. The next section illustrates its use.
Using the MSXML 3.0 API
To use the MSXML 3.0 API, you have to build a Document Object Model (DOM) for the XML data and the XSL template source. Then you transform the XML data to HTML using the XSL template. The following code fragments show how this is done. ' LoadXMLDoc - Returns the XML Document object to the caller. It's used to load' XML and XSL strings, files, or URLs.' On Entry:' objDOMXML - The MSXML2.DOMDocument object to load.' varXML - If it's an XML string, load it into the default DOM document.' If it's a URI string, load the file or URL.' If it's an object, just return it.'Private Sub LoadXMLDoc(objDOMXML As MSXML2.DOMDocument, varXML As Variant) Dim strURI As String If InStr(varXML, "<") > 0 Then 'This is a string because < is not valid in a filename objDOMXML.loadXML varXML Else 'Else load from URI objDOMXML.Load varXML End IfEnd Sub' TransformXML: Takes the XML string or URI and transforms it with the XSL string or URI.' On Entry:' varXML - an XML string, or a URI to an XML file.' varXSL - an XSL string, or a URI to an XSL file.' On Exit: A string that contains the HTML. 'Private Function TransformXML(varXML As Variant, varXSL As Variant) As String Dim objXML As New MSXML2.DOMDocument Dim objXSL As New MSXML2.DOMDocument On Error GoTo TransformXMLErrorHandler TransformXML = "" LoadXMLDoc objXML, varXML If objXML.parseError <> 0 Then TransformXML = MakeParseError(objXML) Exit Function End If LoadXMLDoc objXSL, varXSL If objXSL.parseError <> 0 Then TransformXML = MakeParseError(objXSL) Exit Function End If TransformXML = objXML.transformNode(objXSL) Exit Function TransformXMLErrorHandler: TransformXML = "Error " & Err.Number & " in TransformXML. Error is " & _ Err.Description & "." End Function' MakeParseError: - Makes a nice HTML error message for display in a browser.' On Entry:' objXML - the MSXML2.DOMDocument that caused the error.'Private Function MakeParseError(objXML As MSXML2.DOMDocument) As String Dim nIdx As Integer Dim strSpaces As String strSpaces = String(objXML.parseError.linepos, " ") MakeParseError = "<html><title>XML Parse Error</title><body>" MakeParseError = MakeParseError & "<font size=4>XML Error loading '" & _ objXML.parseError.url & "'</font>" & _ "<p><b><font size=2>" & objXML.parseError.reason & _ "</b></p></font>" If objXML.parseError.Line > 0 Then MakeParseError = MakeParseError & "<p><font size=3><XMP>" & _ "at line " & objXML.parseError.line & ", character " & _ objXML.parseError.linepos & _ vbCrLf & objXML.parseError.srcText & _ vbCrLf & strSpaces & "^" & _ "</xmp></font></p>" End If MakeParseError = MakeParseError & "</body></html>"End Function
The LoadXMLDoc function initializes an object of the type MSXML2.DOMDocument with the contents of the XML or XSL data stream. The data stream may be a string or a URI. Notice that the function uses different methods to initialize the object when the input source is a string, versus when the input source is a URI. The code fragment uses the loadXML method to load a string of XML or XSL directives into the document. The code fragment uses the Load method to load a URI. I am not sure why the developers of the API chose to implement the interface like this, because it requires the programmer to figure out whether the string is data or a URI. In any case, the code fragment assumes that if the string has a "<" character in it, it must be a data stream, not a URI, since this character is not a valid character for a URI.
The TransformXML function calls the LoadXMLDoc function. The TransformXML function has two parameters. The first parameter specifies the XML data stream or URI. The second parameter specifies the XSL data stream or URI. First, the TransformXML function creates a separate instance of the MSXML2.DOMDocument object for the XML data and the XSL data. Then it calls the LoadXMLDoc function to build a DOM for each data stream. After each call, the function checks the parseError object for errors. If an error occurs, an error message is returned from the MakeParseError function. The MakeParseError function is described in the Handling Errors section below. We will skip this for now.
If the function successfully loads both data streams, the function calls the XML document's transformNode method. It passes the XSL document as a parameter, so that the transformNode method can convert the XML data to HTML. The transformNode method returns an HTML string, which can be displayed in a browser.
Handling Errors
The MSXML2.DOMDocument object returns error information in the parseError object. The default property of the parseError object is the errorCode property. It contains the last error that occurred when the document was built. If the errorCode property returns zero, no error has occurred. Otherwise, the parseError object contains more details. The following table shows the other properties and methods of the parseError object.
Property or Method Name |
Description |
Filepos |
The absolute position in the source file where the error occurred. |
Line |
The line number in the source file where the error occurred. |
Linepos |
The column where the error occurred. |
Reason |
The description of the error. |
SourceText |
The source text of the line where the error occurred. |
url |
The url of the source file. |
The following code fragment generates an HTML page that shows the location of the error, including the source text of the line where the error occurred and a pointer to the column. The TransformXML function that is described in the previous section uses this function to return errors that occurred in the LoadXMLDoc function. ' MakeParseError - Makes a nice HTML error message for displaying in a browser.' On Entry:' objXML - The MSXML2.DOMDocument that caused the error.'Private Function MakeParseError(objXML As MSXML2.DOMDocument) As String Dim nIdx As Integer Dim strSpaces As String strSpaces = String(objXML.parseError.linepos, " ") MakeParseError = "<html><title>XML Parse Error</title><body>" MakeParseError = MakeParseError & "<font size=4>XML Error loading '" & _ objXML.parseError.url & "'</font>" & _ "<p><b><font size=2>" & objXML.parseError.reason & _ "</b></p></font>" If objXML.parseError.Line > 0 Then MakeParseError = MakeParseError & "<p><font size=3><XMP>" & _ "at line " & objXML.parseError.line & ", character " & _ objXML.parseError.linepos & _ vbCrLf & objXML.parseError.srcText & _ vbCrLf & strSpaces & "^" & _ "</xmp></font></p>" End If MakeParseError = MakeParseError & "</body></html>"End Function
I changed an XSL directive in my sample XSL file in order to generate an error page so that you can see how expressive it is. The following image illustrates the results after I remove a double quote from one of the tags in the XSL file.
Observations and Suggestions
The Microsoft MSXML 3.0 API only works on machines that run a version of the Windows operating system. If your client's applications are targeted to the Windows operating system, take advantage of this API. It is fast, and its XSL error locator provides decent information.
Packaging the MSXML 3.0 API for deployment with your application has one drawback. The file msxml3.dll has two dependencies, both of which are missed by the Microsoft Packaging and Deployment Wizard that comes with Visual Basic 6.0. They are msxmla.dll and msxmlr.dll. These files are static dynamic link libraries (DLLs) and do not need to be registered like a COM server does. Nonetheless, they are dependencies of the msxml3.dll, so you will have to manually add them to the package.
Also, the Microsoft Packaging and Deployment Wizard thinks that these dependent files have to be registered like self-registering DLLs. This is not true and you will have to remove the "(DLLSelfRegister)" property for each of these files in the setup.lst manifest that gets created by the Packaging and Deployment Wizard. If you do not remove this property, the installation will display non-fatal errors to the user that require the user to click "OK" to continue with the installation.