Answered Can't cause MSXML 6 XSD validation error

  • Monday, July 30, 2012 9:50 PM
     
      Has Code

    Hi folks,

    VBA in Excel 2007, MSXML 6 - I'm trying to test that validation against an XSD I developed will fail if there are problems in documents associated with the schema.  I've been able to trigger validation errors against this schema using the Eclipse (Helios) XML tools, but I can't seem to cause MSXML 6 validation to fail unless it's something like basic well-formedness of the data document.  The schema document itself loads and validates without problems in MSXML 6.  I've tried 1) setting parseOnLoad true for the data document, 2)doing a manual validate() on the data document, and also adding the schema to a schemaCache and validating against that.  None of them will trip, again, unless it's a basic well-formedness problem.

    It's been a while since I've had to do this, and I'm guessing I'm somehow not getting the namespaces wired correctly.  Would appreciate it if someone could let me know if the cause of the problem jumps out at them.

    Here's the test code:

    Sub checkSchema()
        Dim vMyErr As Variant
        
        Dim oXSDDoc As DOMDocument60
        Set oXSDDoc = New DOMDocument60
        oXSDDoc.async = False
        
        'Load XML Schema from a file
        oXSDDoc.validateOnParse = True
        oXSDDoc.Load (ThisWorkbook.Path & "\PSTTLTD2.xsd")
        If oXSDDoc.parseError.ErrorCode <> 0 Then
            Set vMyErr = oXSDDoc.parseError
            MsgBox "XML parsing error " + vMyErr.reason
        End If
        
        oXSDDoc.Validate
        If oXSDDoc.parseError.ErrorCode <> 0 Then
            Set vMyErr = oXSDDoc.parseError
            MsgBox "XML parsing error " + vMyErr.reason
        End If
        'Load XML document from a file
        Dim oSourceDoc As DOMDocument60
        Set oSourceDoc = New DOMDocument60
        oSourceDoc.async = False
        
        oSourceDoc.validateOnParse = True
        oSourceDoc.Load (ThisWorkbook.Path & "\XMLFinalSchemaTestDoc.xml")
        If oSourceDoc.parseError.ErrorCode <> 0 Then
            Set vMyErr = oSourceDoc.parseError
            MsgBox "XML parsing error " + vMyErr.reason
        End If
        oSourceDoc.Validate
        If oSourceDoc.parseError.ErrorCode <> 0 Then
            Set vMyErr = oSourceDoc.parseError
            MsgBox "XML parsing error " + vMyErr.reason
        End If
        
        'Validate with Schema Cache
        'Reload schema into cache.
        Set oXSDDoc = New DOMDocument60
        oXSDDoc.async = False
        oXSDDoc.Load (ThisWorkbook.Path & "\PSTTLTD2.xsd")
        Set oSchemaCache = New XMLSchemaCache60
        oSchemaCache.Add "urn:histogramList", oXSDDoc
        
        Set oSourceDoc.Schemas = oSchemaCache
        oSourceDoc.Validate
        If oSourceDoc.parseError.ErrorCode <> 0 Then
            Set vMyErr = oSourceDoc.parseError
            MsgBox "XML parsing error " + vMyErr.reason
        End If
    End Sub

    Here's the schema:

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema targetNamespace="urn:histogramList"
          xmlns:xs="http://www.w3.org/2001/XMLSchema"
          xmlns:hL="urn:histogramList"
          elementFormDefault="qualified">
        <xs:element name="HistogramList">
           <xs:complexType>
              <xs:sequence>
                 <xs:element name="Histogram" minOccurs="1" maxOccurs="unbounded">
                    <xs:complexType>
                       <xs:sequence>
                         <xs:element name="DataRecord" minOccurs="1" maxOccurs="unbounded">
                            <xs:complexType>
                               <xs:sequence>
                                   <xs:element name="Start" type="xs:integer" minOccurs="1" maxOccurs="1"/>
                                   <xs:element name="Stop" type="xs:integer" minOccurs="1" maxOccurs="1"/>
                                   <xs:element name="NumberOf" type="xs:integer" minOccurs="1" maxOccurs="1"/>
                                </xs:sequence>
                            </xs:complexType>
                         </xs:element>
                      </xs:sequence>
                      <xs:attribute name="ResourceName" use="required">
                         <xs:simpleType>
                            <xs:restriction base="xs:string">
                               <xs:pattern value="([a-zA-Z]([a-zA-Z0-9]|_|-)*){1}(\.([a-zA-Z]([a-zA-Z0-9]|_|-)*){1})*"/>
                            </xs:restriction>
                         </xs:simpleType>
                      </xs:attribute>
                      <xs:attribute name="HistogramType" type="xs:NMTOKENS" use="required"/>
                   </xs:complexType>
                </xs:element>
              </xs:sequence>
           </xs:complexType>
        </xs:element>
     </xs:schema>

    Here's a snippet of the XML document that I can't get to fail validation in MSXML - note that there is a missing required attribute on the <Histogram> element, and the first <DataRecord> element is actually misnamed "xDataRecord":

    <?xml version="1.0"?> <HistogramList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:histogramList PSTTLTD2.xsd" xmlns="urn:histogramList"> <Histogram HistogramType="Net Usage"> <xDataRecord><Start>7632000</Start><Stop>7660800</Stop><NumberOf>0</NumberOf></xDataRecord> <DataRecord><Start>7660800</Start><Stop>7689600</Stop><NumberOf>0</NumberOf></DataRecord> <DataRecord><Start>7689600</Start><Stop>7718400</Stop><NumberOf>0</NumberOf></DataRecord> <DataRecord><Start>7718400</Start><Stop>7747200</Stop><NumberOf>-6</NumberOf></DataRecord>

     

    The XSD file is co-located with both the spreadsheet containing the VBA code, and the XML data document, so, as near as I can tell, the filename without a path should be valid (in any event, nothing complains that it can't locate the XSD, and the same simple location format reference also works in Eclipse when the XSD is in the same workspace).  However, note that I also tried a file reference in the following (example) format for the schema location:

    urn:MyData file://C://Documents and Settings//All Users//Application Data//My Application//MyData.xsd

    The longer format didn't seem to make any difference.)

    Thanks for any help!


    • Edited by linearprism Monday, July 30, 2012 9:54 PM Corrected formatting glitch in VBA code block.
    •  

All Replies

  • Tuesday, July 31, 2012 12:02 PM
     
     Answered Has Code

    When I used MSXML 6 to perform schema validation then I simply added the schema to a schema collection, set that as the schemas property and validated while loading the document; here is a sample (with VBScript but of course the API to use is the same with VBA and early binding):

    Dim xmlDoc, schemaCache
    
    Set xmlDoc = CreateObject("Msxml2.DOMDocument.6.0")
    
    Set schemaCache = CreateObject("Msxml2.XMLSchemaCache.6.0")
    schemaCache.add "urn:histogramList", "test2012073101.xsd"
    
    xmlDoc.schemas = schemaCache
    
    xmlDoc.validateOnParse = True
    xmlDoc.setProperty "MultipleErrorMessages", True
    
    If xmlDoc.load("test2012073101.xml") then
      WScript.Echo "Document is well-formed and valid."
    Else
      For Each pErr In xmlDoc.parseError.allErrors
        WScript.Echo "Error " & pErr.reason & " for " & pErr.errorXPath
      Next
    End If

    Now with the input XML being

    <?xml version="1.0"?>
    <HistogramList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:histogramList test2012073101.xsd"
    xmlns="urn:histogramList">
    	<Histogram  HistogramType="Net Usage">
    		<xDataRecord><Start>7632000</Start><Stop>7660800</Stop><NumberOf>0</NumberOf></xDataRecord>
    		<DataRecord><Start>7660800</Start><Stop>7689600</Stop><NumberOf>0</NumberOf></DataRecord>
    		<DataRecord><Start>7689600</Start><Stop>7718400</Stop><NumberOf>0</NumberOf></DataRecord>
    		<DataRecord><Start>7718400</Start><Stop>7747200</Stop><NumberOf>-6</NumberOf></DataRecord>
      </Histogram>
    </HistogramList>

    and the schema being as you posted I get the following error messages as the output:

    Error Erforderliches Attribut 'ResourceName' fehlt.
     for /*[local-name()="HistogramList" and namespace-uri()="urn:histogramList"]/*[local-name()="Histogram" and namespace-u
    ri()="urn:histogramList"][1]
    Error Der Inhalt des Elements '{urn:histogramList}xDataRecord' ist gemäß dem Inhaltsmodell des übergeordneten Elements '
    {urn:histogramList}Histogram' nicht gültig.
    Erwartet: {urn:histogramList}DataRecord.
     for /*[local-name()="HistogramList" and namespace-uri()="urn:histogramList"]/*[local-name()="Histogram" and namespace-u
    ri()="urn:histogramList"][1]/*[local-name()="xDataRecord" and namespace-uri()="urn:histogramList"][1]

    Sorry, I am on a German version of Windows here so the messages MSXML outputs are German but it correctly complaints about the missing attribute and the incorrect child element.

    If you don't want to load the scheme explicitly then I think you can also do

    Dim xmlDoc, schemaCache
    
    Set xmlDoc = CreateObject("Msxml2.DOMDocument.6.0")
    
    'Set schemaCache = CreateObject("Msxml2.XMLSchemaCache.6.0")
    'schemaCache.add "urn:histogramList", "test2012073101.xsd"
    
    'xmlDoc.schemas = schemaCache
    
    xmlDoc.validateOnParse = True
    xmlDoc.resolveExternals = True
    xmlDoc.setProperty "MultipleErrorMessages", True
    
    If xmlDoc.load("test2012073101.xml") then
      WScript.Echo "Document is well-formed and valid."
    Else
      For Each pErr In xmlDoc.parseError.allErrors
        WScript.Echo "Error " & pErr.reason & " for " & pErr.errorXPath
      Next
    End If
    That way the schema is loaded from the location given in the schemaLocation attribute.


    MVP Data Platform Development My blog

    • Marked As Answer by linearprism Tuesday, July 31, 2012 6:29 PM
    •  
  • Tuesday, July 31, 2012 6:33 PM
     
     

    Thanks, Martin.

    I've got it working in VBA if I follow your steps in those precise sequences.