none
Validate XSD against W3 XMLSchema.xsd

    Frage

  • Any suggestions on how I can validate my XSD?

    I would like to have a unit test that checks the validity of my XSD but I can't get past the following error:

    "For security reasons DTD is prohibited in this XML document. To enable DTD processing set the DtdProcessing property on XmlReaderSettings to Parse and pass the settings into XmlReader.Create method."

    This seems to be because the W3 schema definition references DTDs.

    This is the unit test (xUnit):
    namespace MyNamespace.Profile.Test
    {
        using System;
        using System.IO;
        using System.Xml;
        using System.Xml.Schema;
    
        using Xunit;
    
        public class ProfilesSchemaTests
        {
            [Fact]
            public void ShouldValidateProfilesXsd()
            {
                string profilesXsd = "Profiles.xsd";
                Assert.DoesNotThrow(() => ValidateXsd(profilesXsd));
            }
    
            private static void ValidateXsd(string path)
            {
                const string W3Schema = "http://www.w3.org/2001/XMLSchema.xsd";
    
                var config = new XmlReaderSettings { ValidationType = ValidationType.Schema };
                config.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
                config.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
                config.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
                config.DtdProcessing = DtdProcessing.Parse;
                config.XmlResolver = null;
                config.ValidationEventHandler += ValidationCallBack;
                config.Schemas.Add(null, W3Schema);
    
                using (var reader = XmlReader.Create(path, config))
                {
                    while (reader.Read())
                    {
                    }
                }
            }
    
            private static void ValidationCallBack(object sender, ValidationEventArgs validationEventArgs)
            {
                Console.WriteLine(
                    validationEventArgs.Severity == XmlSeverityType.Warning
                        ? "\tWarning: Matching schema not found.  No validation occurred. {0}"
                        : "\tValidation error: {0}",
                    validationEventArgs.Message);
            }
        }
    }
    


    Freitag, 4. Mai 2012 08:35

Antworten

  • First of all, if you load a schema into an XmlSchemaSet and then Compile that XmlSchemaSet the schemas in the schema set are validated so you do not even need to load the W3C schema for schemas.

    If you nevertheless want to do that then create XmlReaderSettings with DtdProcessing set to parse where you then load the W3C schema with those settings e.g.

       using (XmlReader xr = XmlReader.Create(W3Schema, new XmlReaderSettings() { DtdProcessing = DtdProcessing.Parse }))

      {

         config.Schemas.Add(null, xr);

      }

    That's code for .NET 4.0, for earlier versions of .NET use XmlReaderSettings with ProhibitDtd set to false.

    Also keep in mind that at least for DTDs for XHTML the W3C has put a policy in place to respond with 503 unavailable, I don't know what happens for the schema for schemas or associated DTDs but it might be a good idea to use a local cache of the files if you need to regularly do validation: http://msdn.microsoft.com/en-us/library/system.xml.resolvers.xmlpreloadedresolver.aspx.


    MVP Data Platform Development My blog

    • Als Antwort markiert Bogle Freitag, 4. Mai 2012 14:23
    Freitag, 4. Mai 2012 09:19

Alle Antworten

  • First of all, if you load a schema into an XmlSchemaSet and then Compile that XmlSchemaSet the schemas in the schema set are validated so you do not even need to load the W3C schema for schemas.

    If you nevertheless want to do that then create XmlReaderSettings with DtdProcessing set to parse where you then load the W3C schema with those settings e.g.

       using (XmlReader xr = XmlReader.Create(W3Schema, new XmlReaderSettings() { DtdProcessing = DtdProcessing.Parse }))

      {

         config.Schemas.Add(null, xr);

      }

    That's code for .NET 4.0, for earlier versions of .NET use XmlReaderSettings with ProhibitDtd set to false.

    Also keep in mind that at least for DTDs for XHTML the W3C has put a policy in place to respond with 503 unavailable, I don't know what happens for the schema for schemas or associated DTDs but it might be a good idea to use a local cache of the files if you need to regularly do validation: http://msdn.microsoft.com/en-us/library/system.xml.resolvers.xmlpreloadedresolver.aspx.


    MVP Data Platform Development My blog

    • Als Antwort markiert Bogle Freitag, 4. Mai 2012 14:23
    Freitag, 4. Mai 2012 09:19
  • Thanks, Martin.

    I've added a unit test that uses Compile to validate the schema. That's very useful to know.

    I've also updated my original unit test to load the W3C schema with an XmlReader and the DtdProcessing flag, as you showed.

    Both tests now pass. :)

    Unfortunately they still pass even if I load in a schema that is clearly incorrect (and other tools like XMLFox and XMLPad know is invalid):

    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema elementFormDefault="qualified" version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="Id" type="xs:nonesense" />
      <xs:element name="DisplayName" type="xs:string" />
      <xs:element name="Verified" type="xs:boolean" />
      <xs:element name="IsPrimary" type="xs:boolean" />
      <xs:complexType name="PhoneNumber">
        <xs:sequence>
          <xs:element name="CountryCode" type="xs:string" />
          <xs:element name="NationalNumber" type="xs:string" />
          <xs:element name="IsMobile" type="xs:boolean" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="Profile">
        <xs:sequence>
          <xs:element minOccurs="1" maxOccurs="10" name="PhoneNumbers" />
        </xs:sequence>
      </xs:complexType>
    </xs:schema>
    

    How can that be?



    Richard Bogle

    Freitag, 4. Mai 2012 13:37
  • Once you set up a ValidationEventHandler I don't think the validating XmlReader will throw any exceptions, it simply calls your event handler for any validation error and warning. So if you want your test code to throw an exception then you will need to do that in your code, perhaps by setting a boolean member "valid" to true before the while loop, then setting it to false in the ValidationEventHandler if an error is reported and then to throw an exception in your code after the while loop if that "valid" member variable is false.

    As for the XmlSchemaSet and the Compile method, for me the short snippet

                XmlSchemaSet schemaSet = new XmlSchemaSet();
                schemaSet.Add(null, "../../XMLSchema1.xsd");
                schemaSet.Compile();
    where "XMLSchema1.xsd" is your posted schema throws an exception "Unhandled Exception: System.Xml.Schema.XmlSchemaException: Type 'http://www.w3.org/2001/XMLSchema:nonesense' is not declared.".


    MVP Data Platform Development My blog

    Freitag, 4. Mai 2012 13:50
  • My mistake with the Compile unit test was that I'd loaded the schema into a Schema object before passing it to the SchemaSetCollection. Using the Add() method with the URI worked. Hooray, I have a (correctly) failing test!

    I'll give up on the other unit test. It takes longer to run and I can't get it to fail.


    Richard Bogle

    Freitag, 4. Mai 2012 14:23