Search code examples
c#xmlincludeschemaredefinition

Compiling a Schema containing redefinitions in C#


When reading a schema containing <xs:redefine> tags and trying to compile it using a schema set, I get this exception:

'SchemaLocation' must successfully resolve if <redefine>
contains any child other than <annotation>

I tried many workarounds unsuccessfully like parsing the schemas recursively and adding them to the schema set before compilation and even by adding them as a reference. Still the schema doesn't compile. Example of what was tried (parsing the main xsd and then trying to compile the resulting 'XmlSchemas' after a call to this recursive function):

private void AddRecursive (XmlSchemas xsds, XmlSchema schema)
{
    foreach (XmlSchemaExternal inc in schema.Includes) {
        String schemaLocation = null;
        schemaLocation = inc.SchemaLocation;
        XmlSchema xsd;
        using (FileStream stream = new FileStream (schemaLocation, FileMode.Open, FileAccess.Read)) {
            xsd = XmlSchema.Read (stream, null);
            xsds.Add (xsd);
            xsds.AddReference (xsd);
        }
        AddRecursive (xsds, xsd);
    }
}

What is the correct way to handle such schemas? Why can't the schema compiler resolve the added schemas itself?


Solution

  • The problem with reading the XML schema using the Stream-based overload is that there is no base uri available to the XML Schema reader. If your xsd:redefine uses a relative URI in the schemaLocation attribute, than the default resolver will not be able to find the schema being redefined - hence the error message you're getting.

    I am providing you with the following configuration to get you going, at least in understanding how this is working. Save the two schemas and the test script in the same folder, update the paths in the script and run the C# script. It'll give you this output:

    QN: http://tempuri.org/XMLSchema.xsd:TRedefine, SourceUri: file:///D:/.../.../Redefine.xsd
    QN: http://www.w3.org/2001/XMLSchema:anyType, SourceUri: 
    

    If you update the script to use the Stream-based overload, you'll get the error message from your post.

    Error line 20:      xset.Add(XmlSchema.Read(File.Open    (@"D:\...\...\Redefine.xsd", FileMode.Open), null));
        'SchemaLocation' must successfully resolve if <redefine> contains any child other than     <annotation>.
    'SchemaLocation' must successfully resolve if <redefine> contains any child other than     <annotation>.
    Error Line 21: xset.Add(XmlSchema.Read(File.Open    (@"D:\...\...\Redefine.xsd", FileMode.Open), null));
    

    Base schema:

    <?xml version="1.0" encoding="utf-8" ?>
    <xsd:schema targetNamespace="http://tempuri.org/XMLSchema.xsd"
        elementFormDefault="qualified"
        xmlns="http://tempuri.org/XMLSchema.xsd"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <xsd:complexType name="TRedefine">
            <xsd:sequence>
                <xsd:element name="base" type="xsd:string"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:schema>
    

    The schema that redefines:

    <?xml version="1.0" encoding="utf-8"?>
    <!--XML Schema generated by QTAssistant/XSR Module (http://www.paschidev.com)-->
    <xsd:schema xmlns="http://tempuri.org/XMLSchema.xsd" attributeFormDefault="unqualified"     elementFormDefault="qualified" targetNamespace="http://tempuri.org/XMLSchema.xsd"     xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <!-- Put a full path here.
      <xsd:redefine schemaLocation="D:\...\...\Base.xsd">
        -->
        <xsd:redefine schemaLocation="Base.xsd">
            <xsd:complexType name="TRedefine">
                <xsd:complexContent>
                    <xsd:extension base="TRedefine">
                        <xsd:sequence/>
                    </xsd:extension>
                </xsd:complexContent>
            </xsd:complexType>
        </xsd:redefine>
    </xsd:schema>
    

    A test script:

    using System;
    using System.IO;
    using System.Xml;
    using System.Xml.Schema;
    class Script
    {
        public static void Main()
        {
            // Enter your code below
            // Generated by QTAssistant (http://www.paschidev.com)
            XmlSchemaSet xset = new XmlSchemaSet();
    
            // One way of doing using an XmlReader - it'll work with relative URIs.
            using(XmlReader reader = XmlReader.Create(@"D:\...\...\Redefine.xsd"))
            {
                xset.Add(XmlSchema.Read(reader, null));
            }
    
            // The other way, using stream, requires all external URIs - xsd:include,     xsd:import and xsd:redefine 
            // to be absolute
            //xset.Add(XmlSchema.Read(File.Open(@"D:\...\...\Redefine.xsd", FileMode.Open), null));
    
            xset.Compile();
            Console.WriteLine(xset.IsCompiled);
            foreach(XmlSchemaType type in xset.GlobalTypes.Values) 
            {
                Console.WriteLine("QN: {0}, SourceUri: {1}", type.QualifiedName,     type.SourceUri);
            }
        }
    }