Inline Schemas

 

Stan Kitsis
Microsoft Corporation

September 2005

Applies to:
   XML
   Schema

Summary: Inline schemas are XML schema definitions included inside XML instance documents. Like external schema documents, inline schemas can be used to validate that the instance matches the schema constraints. By default, System.xml disables processing of inline schemas; to enable them, set the ProcessInlineSchema flag. In general, inline schemas behave the same way as xsi:schemaLocation or xsi:noNamespaceSchemaLocation attributes defined on the first element (in document order) that uses namespaces defined in inline schemas. This article summarizes the technical details that you must be careful to handle properly when schemas are contained inline rather that referenced externally.

Contents

Introduction
Technical Details
Wrapping up

Introduction

Inline schemas are XML schema definitions included inside XML instance documents. Like external schema documents, inline schemas can be used to validate that the instance matches the schema constraints. Likewise, the syntax and semantics of inline schemas are the same as for external schemas. Inline schemas can be useful in a number of situations, including:

  • An architecture uses internal DTDs, and the developers wish to preserve that design pattern.
  • It is difficult to access external files or URLs, e.g. for security or platform reasons.
  • There is much diversity in the set of schemas and instances that a system must process, so it is easiest to simply keep the schema as an integral part of the instance.

Technical Details

The W3C Schema Recommendation allows, but does not mandate, support for inline schemas. Few other XML Schema implementations besides those by Microsoft actually do support inline schemas. So, by default, System.xml disables processing of inline schemas. To enable them, you need to set ProcessInlineSchema flag:

XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
XmlReader valReader = XmlReader.Create(url, settings);

If this flag is not set, System.Xml will validate inline schemas as content of the parent elements.

The following is an example of using inline schemas:

<?xml version="1.0" encoding="utf-8" ?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="foo">
    <xsd:element name="a" type="xsd:string"/>
  </xsd:schema>
  <f:a xmlns:f="foo">
    ... this will be validated with schema "foo" ...
  </f:a>
</root>

In this example, the inline schema appears as a child of the root element. Because of this, it is impossible to validate the root element using inline schemas. To validate the root element in the above example, you need to provide an external schema and this schema should have an extension point which allows the inclusion of the <xs:schema> element followed by an element of the namespace "foo":

<?xml version="1.0" encoding="utf-8" ?> 
<xs:schema elementFormDefault="qualified"
           targetNamespace =" http://mySchemas/root" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:any namespace="##any" minOccurs="2" maxOccurs="unbounded"/>        
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

MSXML enforces this rule and will report an error if your schema does not have these extension points. System.xml requires an extension point for elements from the namespace "foo", but does not require an extension point for the <xs:schema> element itself. This behavior might change in the future to match MSXML.

In general, inline schemas behave the same way as xsi:schemaLocation or xsi:noNamespaceSchemaLocation attributes defined on the first element (in document order) that uses namespaces defined in inline schemas. So the following two examples are equivalent:

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <x>
    <someContent/>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        targetNamespace="foo">
        <xsd:element name="a" type="xsd:string"/>
    </xsd:schema>
  </x>
  <f:a xmlns:f="foo">
    ... this will be validated with schema "foo" ...
  </f:a>
</root>

Equivalent to
<?xml version="1.0" encoding="utf-8" ?>
<root>
  <x>
    <someContent/>
  </x>
  <f:a xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
       xmlns:f="foo"
       xsi:schemaLocation="foo some-external-location">
    ... this will be validated with schema "foo" ...
  </f:a>
</root>

As with external schemas, elements are identified by their namespaces. If targetNamespace attribute is not set for your inline schema, it will be used to validate elements that belong to no namespace. Inline schemas with no targetNamespace defined do not take their parent element's namespace.

<f:root xmlns:f="foo">
  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="a" type="xsd:string"/>
  </xsd:schema>
  <a> ... this will be validated with schema above ... </a>
</f:root>

You cannot have an inline schema defined inside the elements that belong to its target namespace.

<?xml version="1.0" encoding="utf-8" ?>
<f:root  xmlns:f="foo">   This element is not validated
  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    targetNamespace="foo">
      ERROR: this inline schema appears inside 
      the element it is supposed to validate
  </xsd:schema>
</root>

Furthermore, you cannot have elements appear in the document prior to the inline schema that defines their namespace. This will be reported as an error.

<?xml version="1.0" encoding="utf-8" ?>
<root  xmlns:f="foo">
  <f:b>This will not be validated</f:b>
  <xsd:schema xmlns:xsd=http://www.w3.org/2001/XMLSchema

    targetNamespace="foo">  This is an ERROR

    <xsd:element name="a" type="xsd:string"/>
    <xsd:element name="b" type="xsd:string"/>
  </xsd:schema>
  <f:a>This will be validated with schema "foo"</f:a>
</root>

You can have more than one inline schema in your document:

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:schema targetNamespace="foo">
    <xsd:element name="a" type="xsd:string"/>
  </xsd:schema>
  <xsd:schema targetNamespace="bar">
    <xsd:element name="b" type="xsd:string"/>
  </xsd:schema>
  <f:a xmlns:f="foo">This will be validated with schema "foo"</f:a>
  <b:b xmlns:b="bar">This will be validated with schema "bar"</b:b>
</root>

You can also have multiple inline schemas that define the same target namespace as long as no elements or attributes from that namespace were processed. This is valid:

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:f="foo">
  <xsd:schema targetNamespace="foo">
    <xsd:element name="a" type="xsd:string"/>
  </xsd:schema>   
  <xsd:schema targetNamespace="foo">
    <xsd:element name="b" type="xsd:string"/>
  </xsd:schema>
  <f:a>This will be validated with schema "foo"</f:a>
  <f:b>This will be validated with schema "foo"</f:b>
</root>

The following is invalid:

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:f="foo">
  <xsd:schema targetNamespace="foo">
    <xsd:element name="a" type="xsd:string"/>
  </xsd:schema>
  <f:a>This will be validated with schema "foo"</f:a>

  <xsd:schema targetNamespace="foo">  This is an ERROR

    <xsd:element name="b" type="xsd:string"/>
  </xsd:schema>
  <f:b>This will be validated with schema "foo"</f:b>
</root>

For an example of using System.xml to process an instance file against an inline schema, read Validation with an Inline XML Schema

Wrapping up

To sum up, there are cases in which it is desirable to bundle the schema for an XML document right in the document itself. System.xml supports XML validation against inline schemas only if the ProcessInlineSchema flag is set. There are a few additional details that you must be careful to handle properly when schemas are contained inline rather that referenced externally, so use this feature of System.xml with care.