PRB: MSXML 4.0 SAX Parser Raises Error Event Before startElement Event (315504)



The information in this article applies to:

  • Microsoft XML 4.0

This article was previously published under Q315504

SYMPTOMS

When you use the MSXML 4.0 Simple API for XML (SAX) parser to validate an element that contains an attribute that is not valid (for example, if the attribute is not defined in the schema, or the attribute contains a value that is not valid), the SAX parser raises the error event of ISAXErrorHandler (IVBSAXErrorHandler) before the parser raises the startElement event of ISAXContentHandler (IVBSAXContentHandler). When the SAX parser raises the error event, only the line number and column number information that is associated with ISAXLocator is available to identify the faulty attribute, instead of the element name that contains the attribute.

CAUSE

Before the MSXML SAX parser fires the startElement event, the parser parses and validates the attributes on the element, builds the ISAXAttributes attribute collection, and then passes the ISAXAttributes attribute collection as an input parameter to the SAX ContentHandler interface (ISAXContentHandler::startElement), as follows:
HRESULT STDMETHODCALLTYPE ISAXContentHandler::startElement( 
            /* [in] */ wchar_t __RPC_FAR *pwchNamespaceUri,
            /* [in] */ int cchNamespaceUri,
            /* [in] */ wchar_t __RPC_FAR *pwchLocalName,
            /* [in] */ int cchLocalName,
            /* [in] */ wchar_t __RPC_FAR *pwchRawName,
            /* [in] */ int cchRawName,
            /* [in] */ ISAXAttributes __RPC_FAR *pAttributes)
				
If a validation error occurs on the attribute, the SAX parser raises the error event before the parser fires the startElement event.

RESOLUTION

To work around this problem, identify the name of the XML element that contains an attribute or attribute value that is not valid when you use the SAX validation feature in MSXML 4.0. To do this, either use the line number and column number information that the parser returns to identify the faulty attribute, or use the following method:
  1. Trap and store the SAX validation error code that the SAX parser generates when the parser finds an attribute or attribute value that is not valid in a global variable in the IVBSAXErrorHandler_error procedure.NOTE: In the October 2001 RTM release of MSXML 4.0, this error code is -2147467259.

  2. Check the global variable for the error code in the IVBSAXContentHandler_startElement event procedure that the SAX parser fires afterward to determine whether the element that the parser parses contains an attribute or attribute value that is not valid.
  3. Use the strQName or strLocalName parameters that the parser passes to the IVBSAXContentHandler_startElement event to determine the name of the XML element when the conditional check for the error code for the attribute or attribute value that is not valid evaluates to TRUE.
  4. Clear the global variable each time the check for the error code for the attribute or attribute value that is not valid evaluates to TRUE.

STATUS

This behavior is by design.

MORE INFORMATION

With the MSXML 4.0 release, the SAX parser only supports validation against XML Schema Definition (XSD) schema. Document Type Definition (DTD) and XML-Data Reduced (XDR) schema validation are not supported in this release.

Steps to Reproduce Behavior

  1. Use the following XML schema definition to create and save an XSD schema document named Person.xsd in the root folder of your hard disk:
    <xs:schema targetNamespace="xsdPerson" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="xsdPerson" 
               elementFormDefault="qualified">
    
      <xs:element name="People" type="PeopleData"/>
    
      <xs:complexType name="PeopleData">
            <xs:sequence>
               <xs:element name="Person" type="PersonData" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>    
      </xs:complexType>
    
      <xs:complexType name="PersonData">
            <xs:sequence>
               <xs:element name="Name" type="xs:string"/>        
            </xs:sequence>         
            <xs:attribute name="age" type="xs:integer" use="required"/>           
      </xs:complexType>
    
    </xs:schema>
    					
  2. Use the following XML to create and save an XML document named Person.xml in the root folder of your hard disk:
    <?xml version="1.0"?>
    <People xmlns="xsdPerson" xsi:schemaLocation='xsdPerson person.xsd' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
    <Person age="28" rank="1">      
     <Name>Sam</Name> 
    </Person>
    </People>
    					
    NOTE: The <person> element in Person.xml has an attribute that is not valid. The rank attribute has not been defined as an attribute of the <person> element in the schema document.

  3. In Microsoft Visual Basic 6.0, create a new Standard EXE project.
  4. Add a project reference to Microsoft XML, v4.0.
  5. Add a class module to the Visual Basic project and name it SAXValidator. This class module is used to implement the IVBSAXErrorHandler interface to trap and report errors that the parser finds when you parse and validate an XML document.
  6. Paste the following code in the SAXValidator class module:
    Implements MSXML2.IVBSAXErrorHandler
    
    Private Sub IVBSAXErrorHandler_error(ByVal oLocator As MSXML2.IVBSAXLocator, strErrorMessage As String, ByVal nErrorCode As Long)
      Debug.Print nErrorCode & " : " &  strErrorMessage & " Line : " & oLocator.lineNumber
    End Sub
    
    Private Sub IVBSAXErrorHandler_fatalError(ByVal oLocator As MSXML2.IVBSAXLocator, strErrorMessage As String, ByVal nErrorCode As Long)
      Debug.Print  nErrorCode & " : " & strErrorMessage & " Line : " & oLocator.lineNumber
    End Sub
    
    Private Sub IVBSAXErrorHandler_ignorableWarning(ByVal oLocator As MSXML2.IVBSAXLocator, strErrorMessage As String, ByVal nErrorCode As Long)
    
    End Sub 
    					
  7. Add a class module to the Visual Basic project and name it SAXContentHandler. This class module is used to implement the IVBSAXContentHandler interface.
  8. Paste the following code in the SAXContentHandler class module. Note that only the IVBSAXContentHandler_startElement procedure contains code to report the occurrences of the startElement event:
    Implements MSXML2.IVBSAXContentHandler
    
    Private Sub IVBSAXContentHandler_characters(strChars As String)
    
    End Sub
    
    Private Property Set IVBSAXContentHandler_documentLocator(ByVal RHS As MSXML2.IVBSAXLocator)
    
    End Property
    
    Private Sub IVBSAXContentHandler_endDocument()
    
    End Sub
    
    Private Sub IVBSAXContentHandler_endElement(strNamespaceURI As String, strLocalName As String, strQName As String)
    
    End Sub
    
    Private Sub IVBSAXContentHandler_endPrefixMapping(strPrefix As String)
    
    End Sub
    
    Private Sub IVBSAXContentHandler_ignorableWhitespace(strChars As String)
    
    End Sub
    
    Private Sub IVBSAXContentHandler_processingInstruction(strTarget As String, strData As String)
    
    End Sub
    
    Private Sub IVBSAXContentHandler_skippedEntity(strName As String)
    
    End Sub
    
    Private Sub IVBSAXContentHandler_startDocument()
    
    End Sub
    
    Private Sub IVBSAXContentHandler_startElement(strNamespaceURI As String, strLocalName As String, strQName As String, ByVal oAttributes As MSXML2.IVBSAXAttributes)
       Debug.Print "Start Element : " & strQName
    End Sub
    
    Private Sub IVBSAXContentHandler_startPrefixMapping(strPrefix As String, strURI As String)
    
    End Sub
    					
  9. Drag a CommandButton control onto Form1.
  10. Paste the following code in the Click event procedure of the CommandButton control to use Person.xsd to parse and validate Person.xml:NOTE: Modify the paths to the documents if you saved them in a different location.
    Dim rdr As New MSXML2.SAXXMLReader40
    Dim Validator As New SAXValidator
    Dim chandler As New SAXContentHandler
    Dim sc As New MSXML2.XMLSchemaCache40
    
    sc.Add "xsdPerson", "c:\person.xml"
    
    rdr.putFeature "schema-validation", True
    rdr.putFeature "exhaustive-errors", True
    rdr.putProperty "schemas", sc
    
    Set rdr.contentHandler = chandler
    Set rdr.errorHandler = Validator
    
    rdr.parseURL "c:\person.xml"
    
    					
  11. Execute the project, and then click the command button when the form appears. The following output appears in the Visual Basic Immediate window:
    Start Element : People
    -2147467259 : The attribute 'rank' on this element is not defined in the DTD/Schema.
    Line : 3
    Start Element : Person
    Start Element : Name
    					
    The output indicates that when the parser parses the <Person> element and reports the undefined rank attribute for the <Person> element, the parser executes the code in the IVBSAXErrorHandler_error procedure in the SAXValidator class module before the parser executes the code in the IVBSAXContentHandler_startElement procedure in the SAXContentHandler class module.

Modification Type:MajorLast Reviewed:4/12/2002
Keywords:kbprb KB315504