Inline an XML Schema into Your XML Document

A good friend of mine, Derek Noonan, pinged me to ask how to inline an XML Schema into an XML document. For instance, think about a WSDL document that has the schema types inline with the WSDL document itself, you would want to figure out how to pull the schema information from the WSDL document and potentially validate some XML with the schema from that WSDL document. Here is a smaller example to help you see what I mean:

<?xml version="1.0" encoding="utf-8" ?>

<DerekDoc>

<xs:schemaxmlns:xs="https://www.w3.org/2001/XMLSchema"

id="XMLSchema"

xmlns="urn:noonan:derek:demo"

xmlns:mstns="urn:noonan:derek:demo"

targetNamespace="urn:noonan:derek:demo"

elementFormDefault="qualified"

>

<xs:complexType name="customerType">

<xs:sequence>

<xs:element name="firstName" type="xs:string" />

<xs:element name="lastName" type="xs:string" />

</xs:sequence>

</xs:complexType>

<xs:element name="customer" type="customerType">

</xs:element>

</xs:schema>

<customerxmlns="urn:noonan:derek:demo" >

<firstName>Derek</firstName>

<lastName>Noonan</lastName>

</customer>

</DerekDoc>

The schema and the document data are both contained within the element "DerekDoc". With the changes to the XML API in .NET 2.0, this is actually pretty easy to do:

 

using System;

using System.Web;

using System.Xml;

using System.Xml.Schema;

 

public partial class _Default : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

XmlReaderSettings outerSettings = new XmlReaderSettings();

outerSettings.IgnoreWhitespace = true;

 

XmlReader reader = XmlReader.Create(Server.MapPath("xmlfile.xml"),outerSettings);

XmlReaderSettings settings = null;

 

//Move to the first element

reader.MoveToContent();

 

while (reader.Read())

{

if ((reader.LocalName == "schema") && (reader.NamespaceURI == "https://www.w3.org/2001/XMLSchema"))

{

settings = new XmlReaderSettings();

XmlSchema schema = XmlSchema.Read(reader,null);

settings.ValidationType = ValidationType.Schema;

settings.ValidationEventHandler+=new ValidationEventHandler(OnValidate);

settings.Schemas.Add(schema);

}

else

{

XmlReader contents = XmlReader.Create(reader,settings);

 

try

{

//validate the contents of the doc

while (contents.Read()) ;

}

catch (InvalidOperationException)

{

//Stupid bug for nested XmlReaders

//no-op

}

finally

{

contents.Close();

}

 

}

}

reader.Close();

}

 

private void OnValidate(object sender, ValidationEventArgs e)

{

Response.Write(e.Message + "<br>");

}

}

 

Note that I have a catch handler that is a no-operation that catches an InvalidOperationException. It looks like the nested XmlReader named "contents" will move one step too far when the readers are chained together, making the "contents" reader contain an end element called "DerekDoc". Going to see if I can isolate that and then forward a bug report, but the workaround is fairly self-explanatory here.

Man… it seems like forever ago since I worked with the XML APIs directly, it was kind of refreshing to go fight the SOM again.

Thanks to Derek for helping to cure my technical writer's block.