Performing Error Handling with XSLT

 

An XSLT file can generate two types of errors: parse errors and run-time errors. There are ways to check for these errors, and to report them.

The following is a simple HTML file that uses XML data islands to load an XML file and an XSLT style sheet, and to display the results.

<HTML>
  <XML id="source" src="simple.xml"></XML>
  <XML id="style" src="simple.xsl"></XML>
  <SCRIPT event="onload" for="window">
    showResult.innerHTML = source.transformNode(style.XMLDocument);
  </SCRIPT>
  <BODY>
    <DIV id="showResult"></DIV>
  </BODY>
</HTML>

The XML data islands load the XML data from the simple.xml file and the XSLT style sheet from the simple.xsl file, respectively. The call to the transformNode method invokes the XSLT processor, and the resulting HTML is inserted into the page.

If nothing appears, first check the parseError object to see if there was a parsing error in the XML file or style sheet. Parsing errors on data islands do not generate error messages in the browser. If an error occurred, you can retrieve the cause or put an error message into the page.

The following example checks for parsing errors. If errors occur, a function is called to format the error information in a way that is appropriate for insertion into the HTML document.

<HTML>
  <HEAD>
    <TITLE>Simple Error Message Demo</TITLE>
  </HEAD>
  
  <XML id="source" src="review.xml"></XML>
  <XML id="style" src="review.xsl"></XML>
  
  <SCRIPT src="reportErrors.js"></SCRIPT>
  <SCRIPT event="onload" for="window">
    if (source.parseError.errorCode != 0)
      result = reportParseError(source.parseError);
    else
    {
      if (style.parseError.errorCode != 0)
        result = reportParseError(style.parseError);
      else
      {
        try {
          result = source.transformNode(style.XMLDocument);
        }
        catch (exception) {
          result = reportRuntimeError(exception);
        }
      }
    }
    // Insert the results into the page.
    showResult.innerHTML = result;
  </SCRIPT>
  <BODY>
    <DIV id="showResult"></DIV>
  </BODY>
</HTML>

In addition to parsing errors, the preceding example also detects XSLT run-time errors that occur inside calls to the transformNode method. Run-time errors are normally reported to the user through a Microsoft® Internet Explorer error dialog box. However, it is often useful to suppress this dialog box. The try and catch functions in Microsoft JScript® (compatible with the ECMA 262 language specification) allow the error to be suppressed and handled consistently with parsing errors.

The actual formatting of the error information in the previous example is performed by two functions: reportParseError and reportRuntimeError. These functions are located in a separate script file, reportErrors.js. The main HTML page references this script file.

JScript File (reportErrors.js)

// Parse error formatting function  
function reportParseError(error)  
{  
  var s = "";  
  for (var i=1; i<error.linepos; i++) {  
    s += " ";  
  }  
  r = "<font face=Verdana size=2><font size=4>XML Error loading '" +   
      error.url + "'</font>" +  
      "<P><B>" + error.reason +   
      "</B></P></font>";  
  if (error.line > 0)  
    r += "<font size=3><XMP>" +  
    "at line " + error.line + ", character " + error.linepos +  
    "\n" + error.srcText +  
    "\n" + s + "^" +  
    "</XMP></font>";  
  return r;  
}  
// Runtime error formatting function.  
function reportRuntimeError(exception)  
{  
  return "<font face=Verdana size=2><font size=4>XSL Runtime Error</font>" +  
      "<P><B>" + exception.description + "</B></P></font>";  
}  

These two functions return HTML fragments that can be inserted into the HTML page in place of the correct transformation result. This alerts you to a problem.

Reporting an error using this mechanism is also useful in an Active Server Page (ASP). Here is the equivalent code for processing an XML file on the server.

<%@ LANGUAGE = JScript %>
<%
  // Parse error formatting function.
  function reportParseError(error)
  {
    var s = "";
    for (var i=1; i<error.linepos; i++) {
      s += " ";
    }
    r = "<font face=Verdana size=2><font size=4>XML Error loading '" + 
        error.url + "'</font>" +
        "<P><B>" + error.reason + 
        "</B></P></font>";
    if (error.line > 0)
      r += "<font size=3><XMP>" +
      "at line " + error.line + ", character " + error.linepos +
      "\n" + error.srcText +
      "\n" + s + "^" +
      "</XMP></font>";
    return r;
  }
  // Run-time error formatting function.
  function reportRuntimeError(exception)
  {
    return "<font face=Verdana size=2><font size=4>XSL Runtime Error</font>" +
        "<P><B>" + exception.description + "</B></P></font>";
  }
  // Set the source and style sheet locations here.
  var sourceFile = Server.MapPath("simple.xml");
  var styleFile = Server.MapPath("simple.xsl");
  
  // Load the XML.
  var source = Server.CreateObject("Msxml2.DOMDocument.6.0");
  source.async = false;
  source.load(sourceFile);
  // Load the XSL.
  var style = Server.CreateObject("Msxml2.DOMDocument.6.0");
  style.async = false;
  style.load(styleFile);
  if (source.parseError.errorCode != 0)
    result = reportParseError(source.parseError);
  else
  {
    if (style.parseError.errorCode != 0)
      result = reportParseError(style.parseError);
    else
    {
      try {
        result = source.transformNode(style);
      }
      catch (exception) {
        result = reportRuntimeError(exception);
      }
    }
  }
  Response.Write(result);
%>

The code here is essentially the same as that for the client side, with the same error formatting functions and processing. The Server.CreateObject and Response.Write methods are used in place of the client-side functions provided by data islands and the innerHTML method.

See Also

Implementing Error Handling with XSLT and the DOM