Loading a document from a string using XSD

This question came up recently in the forums, and I thought I'd post some sample code to show how to do it.

The idea is this: you can an XML document in a string variable, and you want to load it into a document. You also have an XSD that you want to make sure the XML conforms to. How do you do this?

Let's ignore the XSD part for a bit - how do you get content into an XmlDocument? You can set things up step-by-step: create a reader that returns text in chunks from the string; then an XmlReader that returns XML nodes, and then load an XmlDocument from that reader.

const string text = "<hello><to>the world!</to></hello>";
XmlDocument doc;

doc = new XmlDocument();
using (StringReader reader = new StringReader(text))
using (XmlReader xml = XmlReader.Create(reader))
{
    doc.Load(xml);
}
Console.WriteLine("Root element: " + doc.DocumentElement.Name);

Or, you could use this very handy shortcut.

// Easier version:
doc = new XmlDocument();
doc.LoadXml(text);
Console.WriteLine("Root element: " + doc.DocumentElement.Name);

This is all fine and well, but we haven't done anything with the XSD yet. The LoadXml method doesn't support this directly, but the XmlReader does; we simply need to specify in the reader settings that we want validation to take place.

// With validation:
const string string xsd = "<xsd:schema xmlns:xsd='https://www.w3.org/2001/XMLSchema'>" +
 "<xsd:element name='hello' type='helloType'/>" +
 "<xsd:complexType name='helloType'>" +
 " <xsd:sequence maxOccurs='1'>" +
 " <xsd:element name='to' type='xsd:string'/>" +
 " </xsd:sequence>" +
 "</xsd:complexType></xsd:schema>";
XmlSchema schema;
using (StringReader xsdReader = new StringReader(xsd))
{
    schema = XmlSchema.Read(xsdReader, null);
}

XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.Schemas.Add(schema);
settings.ValidationEventHandler += (sender, args) =>
{
    Console.WriteLine(args.Severity.ToString() + " - " + args.Message);
    if (args.Severity == XmlSeverityType.Error)
        throw new InvalidOperationException(args.Message);
}

using (StringReader reader = new StringReader(text))
using (XmlReader xml = XmlReader.Create(reader, settings))
{
    doc.Load(xml);
}
Console.WriteLine("Root element: " + doc.DocumentElement.Name);

Try playing with the text constant we're using for the XML to see how the validation code we set up reacts when you change different elements.

Note that we're loading things into an XmlDocument, but there are equivalent APIs to do all of this with an XDocument as well.

Enjoy!