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.
|