Tony Vitabile
Tony Vitabile

Reputation: 8594

Why does this XML validate, when it shouldn't?

I have the following XSD files:

ReadFile.xsd:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns="elsag:lprcore" elementFormDefault="qualified" targetNamespace="elsag:lprcore" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:include schemaLocation="Read.xsd" />
  <xs:element name="reads" type="ReadFile" />
  <xs:complexType name="ReadFile">        
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="unbounded" name="read" nillable="true" type="read">
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:schema>

Read.xsd:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns="elsag:lprcore" elementFormDefault="qualified" targetNamespace="elsag:lprcore" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:include schemaLocation="Snapshot.xsd"/>
  <xs:include schemaLocation="GPS.xsd"/>

  <xs:simpleType name="guid">
    <xs:restriction base="xs:string">
      <xs:pattern value="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}" />
    </xs:restriction>
  </xs:simpleType>

  <xs:element name="read" type="read"/>
  <xs:complexType name="read">
    <xs:complexContent mixed="false">
      <xs:extension base="snapshot">
        <xs:sequence>
          <xs:element minOccurs="1" maxOccurs="1" name="timestamp" type="xs:dateTime" />
          <xs:element minOccurs="1" maxOccurs="1" name="plate" type="xs:string" />
          <xs:element minOccurs="0" maxOccurs="1" name="state" type="xs:string" />
          <xs:element minOccurs="1" maxOccurs="1" name="confidence" type="xs:int" />
          <xs:element minOccurs="1" maxOccurs="1" name="overviews">
            </xs:annotation>
            <xs:complexType>
              <xs:sequence>
                <xs:element minOccurs="0" maxOccurs="unbounded" name="snapshot" type="snapshot"/>
              </xs:sequence>
            </xs:complexType>
          </xs:element>
          <xs:element minOccurs="1" maxOccurs="1" name="gps" type="gps" />
        </xs:sequence>
        <xs:attribute name="id" type="guid" use="required" />
        <xs:attribute name="camera" type="xs:string" use="required" />
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
</xs:schema>

Please note that there are more files that make up the XSD, but I don't believe they're relevant to the problem so I did not include them.

I'm using the following code to validate XML files being processed. I want to reject any file that doesn't validate without errors:

StringBuilder validationErrors = new StringBuilder();
inDoc.Validate( schemas, ( o, e ) => {
    validationErrors.AppendLine( e.Message );
} );
if ( !string.IsNullOrWhiteSpace( validationErrors.ToString() ) ) {
    . . .
}

I've passed the following XML file to the code above and the code does not generate any validation error messages for it.

<read>
  <timestamp>2015-07-17T16:20:18.1540000-04:00</timestamp>
  <plate>FED456</plate>
</read>

I would have thought that the lack of the reads tag surrounding the read tag would have caused the XML to fail validation. Is the problem in the validation code or is it in the XSD or is this normal?

EDIT:

Here is the code that initializes the schemas variable:

XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add( "elsag:lprcore", @"XML\ReadFile.xsd" );

Upvotes: 2

Views: 279

Answers (2)

Tony Vitabile
Tony Vitabile

Reputation: 8594

Thanks to information posted in the answer by Glorfindel and the link posted by overslacked, I've been able to get the XML validation in my program to work.

The problem was that the program would not flag an XML file that does not contain a namespace as invalid. The cause is that the XDocument.Validate extension method creates an XmlReader object whose XmlReaderSettings property does not contain the ReportValidationWarnings flag. As a result, the ValidationEventHandler delegate passed to the method is not called for these files.

To make the validation logic work, I defined a new extension method that includes the flag:

internal static class XmlValidationExtension {

    public static void ValidateWithWarnings( this XDocument doc, XmlSchemaSet schemas, ValidationEventHandler validationCallback ) {
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.ValidationType = ValidationType.Schema;
        settings.Schemas.Add( schemas );
        settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
        settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
        settings.ValidationEventHandler += new ValidationEventHandler( validationCallback );

        XmlReader reader = XmlReader.Create( doc.CreateReader(), settings );

        while ( reader.Read() ) ;
    }
}

This is essentially the same exact code from the question linked to by overslacked, but where the XmlReader is created by calling the XDocment object's CreateReader method.

This code now considers any XML file which does not use the correct namespace to be invalid. Any other part of the XML that does not match the XSD is also flagged.

Upvotes: 0

Glorfindel
Glorfindel

Reputation: 22631

Because you have defined

<xs:element name="read" type="read"/>

the read element is a valid root element for your XML. Every element which is an immediate child of <xs:schema> is eligible for being a root element (even those in an included schema).

Upvotes: 1

Related Questions