XML

XMLDOMParseError Object

The XMLDOMParseError object is an extension to the W3C specification. It can be used to get detailed information on the last error that occurred while either loading or parsing a document. The XMLDOMParseError object implements the IXMLDOMParseError interface that has the following properties:

IXMLDOMParseError Properties

Name Description
errorCode Returns the error number or error code as a decimal integer.
filepos Returns the absolute character position in the document where the error occurred.
line Returns the number of the line where the error occurred.
linepos Returns the absolute character position in the line where the error occurred.
reason Returns a description of the source and reason for the error. If the error is in a schema or DTD, it can include the URL for the DTD or schema and the node in the schema or DTD where the error occurred.
srcText Returns the full text of the line that contains the error. If the error cannot be assigned to a specific line, an empty line is returned.
url Returns the URL for the most recent XML document that contained an error.

To see how the IXMLDOMParseError interface is used, we will make a change to the first line of code in the Books.dtd: <!ELEMENT northwind:BOOKS (item)> by removing the northwind: from the line, as shown here:

  <!ELEMENT BOOKS  (item )>

Add another command button to the frmDOCTest form with the name cmdParseError and the caption ParseError. In the click event handler of this button, place the following code:

  Private Sub cmdParseError _Click()
      Dim objXMLDoc As DOMDocument
      Dim objXMLParseError As IXMLDOMParseError
      On Error GoTo cmdParseErrorError
      Set objXMLDoc = New DOMDocument
      objXMLDoc.async = False
      objXMLDoc.Load ("c:\Books.xml")
      'Check whether there was an error parsing the file using the
      'parseError object.
      If objXMLDoc.parseError.errorCode <> 0 Then
          'If there was an error, raise it to jump into error trap.
          Err.Raise objXMLDoc.parseError.errorCode
      End If
      Exit Sub
  'Error Trap
  cmdParseErrorError:
      Set objXMLParseError = objXMLDoc.parseError
      With objXMLParseError
          'Because of the With objXMLParseError, .errorCode is the
          'same as objXMLParseError.errorCode.
          'First check whether the error was caused by a parse error.
          If .errorCode <> 0 Then
              Debug.Print "The following error occurred:" & vbCrLf & _
                   "error code: " & .errorCode & vbCrLf & _
                   "error file position: " & .filepos & vbCrLf & _
                   "error line: " & .Line & vbCrLf & _
                   "error line position: " & .linepos & vbCrLf & _
                   "error reason: " & vbCrLf & .reason & vbCrLf & _
                   "error source text: " & vbCrLf & .srcText & _
                             " Test:cmdParseError"
          Else
              'If the error was not caused by a parse error, use
              'regular Visual Basic error object.
              MsgBox "The following error has occurred:" & vbCrLf & _
                  "Error Description: " & Err.Description & _
                                          vbCrLf & _
                  "Error Source: " & vbCrLf & Err.Source &  _
                             " Test:cmdParseError" & vbCrLf & _
                  "Error Number: " & Err.Number
          End If
      End With
      Set objXMLParseError = Nothing
      Set objXMLDoc = Nothing
  End Sub

Before you actually run this code, take a look at it to see what an error handler in production code should look like. A parse error does not raise its error. After the parse error occurs, the Visual Basic error number (Err.Number) is still 0. Thus, you must use the ParseError object to check for an error after you load an XML document. If there is a parse error, you can raise an error, as was done above, to bring you into the error trap.

The error trap provides a message if the error occurred in parsing the file. If the error was caused for some other reason, the standard Visual Basic Err error object is used. Also notice that the name of the application and the method are included in the source, making it easier to find and fix bugs.

Now you can run the updated application and click the ParseError button. With the change in the DTD, you will receive the following message:

  The following error occurred:
  error code: -1072898035
  error file position: 137
  error line: 3
  error line position: 64
  error reason:
  The element 'northwind:BOOKS' is used but not declared in the
  DTD/Schema.
  error source text:
  <northwind:BOOKS xmlns:northwind="www.northwindtraders.com/PO">
  Test:cmdParseError
  error source text:
  <northwind:BOOKS xmlns:northwind="www.northwindtraders.com/PO">

In this case, because the DTD has no awareness of namespaces, the namespace qualified northwind:BOOKS in the XML document no longer matches the DTD declaration.

To create a different error, change the DTD back to its original form by adding back the northwind:. Remove #FIXED "www. northwindtraders.com/PO" from the second line in the DTD, and the second line will look as follows:

  <!ATTLIST ":BOOKS  xmlns: "CDATA>

Now run the application and click the ParseError button; the error message will look as follows:

  The following error occurred:
  error code: -1072896766
  error file position: 86
  error line: 2
  error line position: 51
  error reason:
  A string literal was expected, but no opening quote character
    was found.
  error source text:
  <!ATTLIST northwind:BOOKS  xmlns:northwind CDATA>
  Test:cmdParseError
  error source text:
  <!ATTLIST northwind:BOOKS  xmlns:northwind CDATA>

Notice that the error source text is now the information from the DTD. The reason might not be that obvious, but by looking at the error reason you will see that you need to include #REQUIRED, #FIXED, or #IMPLIED in the DTD. You must use #FIXED because this is a namespace attribute.