DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 17.4 Validating XML

Problem

You are accepting an XML document created by another source and you want to verify that it conforms to a specific schema. This schema may be in the form of an XSD or XDR schema; alternatively, you want the flexibility to use a DTD to validate the XML.

Solution

Use the XmlValidatingReader to validate XML documents against any descriptor document, such as an XSD (XML Schema), a DTD (Document Type Definition), or an XDR (Xml-Data Reduced):

public static void ValidateXML( )
{
    // create XSD schema collection with book.xsd
    XmlSchemaCollection schemaCollection = new XmlSchemaCollection( );
    // wire up handler to get any validation errors
    schemaCollection.ValidationEventHandler += 
        new ValidationEventHandler(ValidationCallBack);
    // add book.xsd
    schemaCollection.Add(null, @"..\..\Book.xsd");
    // make sure we added
    if(schemaCollection.Count > 0)
    {
        // open the book.xml file
        XmlTextReader reader = new XmlTextReader(@"..\..\Book.xml");
        // set up the validating reader
        XmlValidatingReader validReader = 
            new XmlValidatingReader(reader);

        // set the validation type and add the schema collection
        validReader.ValidationType = ValidationType.Schema;
        validReader.Schemas.Add(schemaCollection);

        // wire up for any validation errors from the validating 
        // reader
        validReader.ValidationEventHandler += 
            new ValidationEventHandler(ValidationCallBack);
        // read all nodes and print out
        while (validReader.Read( ))
        {
            if(validReader.NodeType == XmlNodeType.Element) 
            {
                Console.Write("<{0}", validReader.Name);
                while(validReader.MoveToNextAttribute( ))
                {
                    Console.Write(" {0}='{1}'",validReader.Name,
                        validReader.Value);
                }
                Console.Write(">");
            }
            else if(validReader.NodeType == XmlNodeType.Text)
            {
                Console.Write(validReader.Value);
            }
            else if(validReader.NodeType == XmlNodeType.EndElement)
            {
                Console.WriteLine("</{0}>",validReader.Name);
            }
        }
    }
}

private static void ValidationCallBack(object sender, ValidationEventArgs e) 
{
    Console.WriteLine("Validation Error: {0}", e.Message);
}

Discussion

The Solution illustrates how to use the XmlValidatingReader to validate the book.xml document against a book.xsd XML Schema definition file. DTDs were the original way to specify the structure of an XML document, but it has become more common to use XML Schema since it reached W3C Recommendation status in May 2001. XDR was an early form of the final XML Schema syntax provided by Microsoft, and, while it might be encountered in existing systems, it should not be used for new development.

The first thing to do is create an XmlSchemaCollection to hold our XSD (book.xsd):

// create XSD schema collection with book.xsd
XmlSchemaCollection schemaCollection = new XmlSchemaCollection( );
// wire up handler to get any validation errors
schemaCollection.ValidationEventHandler += 
    new ValidationEventHandler(ValidationCallBack);
// add book.xsd
schemaCollection.Add(null, @"..\..\Book.xsd");

This code also hooks up the schema collection event handler for validation errors to the ValidationCallback function that writes out the validation error message:

private static void ValidationCallBack(object sender, ValidationEventArgs e) 
{
    Console.WriteLine("Validation Error: {0}", e.Message);
}

Once we have the schema collection, we create an XmlTextReader to load the book.xml file and then use the XmlTextReader to create our XmlValidatingReader:

// open the book.xml file
XmlTextReader reader = new XmlTextReader(@"..\..\Book.xml");
// set up the validating reader
XmlValidatingReader validReader = 
    new XmlValidatingReader(reader);

The XmlValidatingReader error handler is also wired up to the ValidationCallback function; we then proceed to roll over the XML document and write out the elements and attributes. Setting the XmlValidationReader.ValidationType to ValidationType.Schema tells the XmlValidatingReader to perform XML Schema validation. To perform DTD validation, use a DTD and ValidationType.DTD, and to perform XDR validation, use an XDR schema and ValidationType.XDR:

    // set the validation type and add the schema collection
    validReader.ValidationType = ValidationType.Schema;
    validReader.Schemas.Add(schemaCollection);

    // wire up for any validation errors from the validating 
    // reader
    validReader.ValidationEventHandler += 
        new ValidationEventHandler(ValidationCallBack);

    // read all nodes and print out
    while (validReader.Read( ))
    {
        if(validReader.NodeType == XmlNodeType.Element) 
        {
                Console.Write("<{0}", validReader.Name);
                while(validReader.MoveToNextAttribute( ))
            {
            Console.Write(" {0}='{1}'",validReader.Name,
                validReader.Value);
            }
            Console.Write(">");
        }
        else if(validReader.NodeType == XmlNodeType.Text)
        {
            Console.Write(validReader.Value);
        }
        else if(validReader.NodeType == XmlNodeType.EndElement)
        {
            Console.WriteLine("</{0}>",validReader.Name);
        }
}

The book.xml file contains the following:

<?xml version="1.0" encoding="utf-8"?>
<Book xmlns="http://tempuri.org/Book.xsd" name="C# Cookbook">
    <Chapter>File System IO</Chapter>
    <Chapter>Security</Chapter>
    <Chapter>Data Structures and Algorithms</Chapter>
    <Chapter>Reflection</Chapter>
    <Chapter>Threading</Chapter>
    <Chapter>Numbers</Chapter>
    <Chapter>Strings</Chapter>
    <Chapter>Classes And Structures</Chapter>
    <Chapter>Collections</Chapter>
    <Chapter>XML</Chapter>
    <Chapter>Delegates And Events</Chapter>
    <Chapter>Diagnostics</Chapter>
    <Chapter>Enums</Chapter>
    <Chapter>Unsafe Code</Chapter>
    <Chapter>Regular Expressions</Chapter>
</Book>

The book.xsd file contains the following:

<?xml version="1.0" ?>
<xs:schema id="NewDataSet" targetNamespace="http://tempuri.org/Book.xsd" xmlns:
mstns="http://tempuri.org/Book.xsd"
    xmlns="http://tempuri.org/Book.xsd" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
    attributeFormDefault="qualified" elementFormDefault="qualified">
    <xs:element name="Book">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Chapter" nillable="true" 
                            minOccurs="0" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:simpleContent 
msdata:ColumnName="Chapter_Text" msdata:Ordinal="0">
                            <xs:extension base="xs:string">
                            </xs:extension>
                        </xs:simpleContent>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
            <xs:attribute name="name" form="unqualified" type="xs:string"/>
        </xs:complexType>
    </xs:element>
</xs:schema>

See Also

See the "XmlValidatingReader Class," "XmlSchemaCollection Class," "ValidationEventHandler Class," "ValidationType Enumeration," and "Introduction to XML Schemas" topics in the MSDN documentation.

    [ Team LiB ] Previous Section Next Section