-->

Validate XSD in C# as if it were an XML: doesn'

2019-07-18 14:44发布

问题:

The short story:

I want to validate an XSD file (all XSDs being XMLs themselves) using an XSD schema, in code, and get the same warnings or errors that Visual Studio displays when opening the same XSD file in its (xml as text) editor.

Visual Studio shows a warning in its xml editor (see below).

My problem is, the validation done in code gives 100% success. No warning, nothing. What am I missing?

The long story:

The XSD file is by definition an XML file, so I'm validating my custom XSD using XML validation against the W3C xsd schema.

Here's the XSD to be validated and a warning as shown by VS 2010:
(click img to zoom)

To spare you the squinting, here's a bit of the warning:

Wildcard '##any' allows element 'Com.Example.Config:permissionConfig', and causes the content model to become ambiguous. A content model must be formed such that [... tl;dr]

This is my custom XSD:

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema 
    xmlns:tns="Com.Example.Config" 
    elementFormDefault="qualified" 
    targetNamespace="Com.Example.Config" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:complexType name="Com.Example.Config.PermissionConfigCT" />
  <xs:complexType name="Com.Example.Config.PermissionsCT">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="unbounded" name="permissionConfig" type="tns:Com.Example.Config.PermissionConfigCT" />

      <!-- next line triggers the warning -->
      <xs:any minOccurs="0" processContents="lax" />

    </xs:sequence>
  </xs:complexType>
</xs:schema>

Checking the schemas used for validation by VS (from menu XML -> Schemas) shows it's using:

  • xsdschema.xsd (FWIW, it's derived from the W3C original schema for XSD, sans the DTD parts)
  • xml.xsd (referenced in the previous xsd, by a relative include)

Both files reside (on my machine) here:

C:\Program Files (x86)\Microsoft Visual Studio 10.0\xml\Schemas

I copied them both in the same directory as the executable, for easy referencing.

For completeness, here's how the xsdschema.xsd defines its namespaces:

<xs:schema 
  targetNamespace="http://www.w3.org/2001/XMLSchema" 
  blockDefault="#all" 
  elementFormDefault="qualified"  
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xml:lang="EN" version="1.0"
  xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense">

  <xs:import namespace="http://www.w3.org/XML/1998/namespace"/>

  <xs:complexType name="openAttrs">
  [...]

...So I went ahead and wrote some quick validating code, using the same XSDs that VS is using. This is the code:

var configXsdPath = "XMLFile1.xml"; 
  //that's my custom XSD file, don't let the extension fool you

var xmlSchemaForXsdPath = "xsdschema.xsd";

var settings = new XmlReaderSettings
    {
        ValidationType = ValidationType.Schema,
        ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings
                        | XmlSchemaValidationFlags.ProcessSchemaLocation
                        | XmlSchemaValidationFlags.ProcessIdentityConstraints
    };


using (var tr = XmlReader.Create(xmlSchemaForXsdPath))
{
    settings.Schemas.Add(XmlSchema.Read(tr, (i_sender, i_args) 
      => {throw new InvalidOperationException(
                 "The validating XSD is itself invalid");} ));
}

settings.ValidationEventHandler += (i_sender, i_args) 
  => { throw new Exception(i_args.Message); };

var reader = XmlReader.Create(configXsdPath, settings);
while (reader.Read())
//parse it all
{ }

...and no exception pops up whatsoever...

Update Next I tried feeding outright invalid XML: I added this element somewhere inside the custom XSD:

<aaa!></aaa>

and the code gives the expected error*:

The element 'schema' in namespace 'http://www.w3.org/2001/XMLSchema' has invalid child element 'aaa'. List of possible elements expected: 'simpleType, complexType, group, attributeGroup, element, attribute, notation, annotation' in namespace 'http://www.w3.org/2001/XMLSchema'.

--

  • I briefly stated at some point that adding invalid XML would not produce any errors. That was a case of PEBKAC.

回答1:

Simply put, what you're trying to achieve - your validator to trip on next line triggers the warning - by validating your XSD against the W3C xsd schema is never going to work. That is called Unique Particle Attribution, something that the XSD language is not capable of describing. The thing is, this is just the beginning; the more XSD features you end up using, the less reliable your proposed validation it's going to be.

If you're really trying to validate an XSD, on .NET at least, use the XmlSchemaSet. To turn on and off the UPA check, this is how you do it.



回答2:

Great insight from Petru Gardea's answer: treating an XSD as an XML only goes so far when validating, so treat it as the XSD that it is instead (or in addition to that)!

It's as easy as this:

var schemas = new XmlSchemaSet();
using (var tr = XmlReader.Create(xsdPath))
{
    schemas.Add(null, tr);
              //null means 'use the target namespace specified in the XSD'
}
//schemas.CompilationSettings.EnableUpaCheck = true; //it's true by default

schemas.Compile();

Running the above code throws XmlSchemaException with the exact description given by Visual Studio:

System.Xml.Schema.XmlSchemaException : Wildcard '##any' allows element 'Com.Example.Config:permissionConfig', and causes the content model to become ambiguous. A content model must be formed such that during validation of an element information item sequence, the particle contained directly, indirectly or implicitly therein with which to attempt to validate each item in the sequence in turn can be uniquely determined without examining the content or attributes of that item, and without any information about the items in the remainder of the sequence.