Recipe15.4.Validating XML


Recipe 15.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 XML schema (XSD or XMLXDR); alternatively, you want the flexibility to use a document type definition (DTD) to validate the XML.

Solution

Use the XmlReaderSettings to create an XmlReader that can validate XML documents against any descriptor document, such as an XSD, a DTD, or an XDR, as shown in Example 15-3.

Example 15-3. Validating XML

 public static void ValidateXml() {      // Create XSD schema collection with book.xsd.      XmlReaderSettings settings = new XmlReaderSettings();      // Wire up handler to get any validation errors.      settings.ValidationEventHandler += settings_ValidationEventHandler;     // Set the validation type to schema.     settings.ValidationType = ValidationType.Schema;     // Add book.xsd.     settings.Schemas.Add(null, XmlReader.Create(@"..\..\Book.xsd"));     // Make sure we added.     if (settings.Schemas.Count > 0)     {         // Open the bookbad.xml file.         using (XmlReader reader = XmlReader.Create(@"..\..\BookBad.xml", settings))         {             // Replace validReader with reader for the whole loop.             while (reader.Read())             {                 if (reader.NodeType == XmlNodeType.Element)                 {                      Console.Write("<{0}", reader.Name);                     while (reader.MoveToNextAttribute())                      {                         Console.Write(" {0}='{1}'", reader.Name,                             reader.Value);                     }                     Console.Write(">");                 }                 else if (reader.NodeType == XmlNodeType.Text)                 {                     Console.Write(reader.Value);                 }                  else if (reader.NodeType == XmlNodeType.EndElement)                 {                     Console.WriteLine("</{0}>", reader.Name);                 }             }         }     } } private static void settings_ValidationEventHandler(object sender,                              ValidationEventArgs e) {  Console.WriteLine("Validation Error Message: {0}", e.Message);  Console.WriteLine("Validation Error Severity: {0}", e.Severity);  if (e.Exception != null)  {     Console.WriteLine("Validation Error Line Number: {0}",              e.Exception.LineNumber);      Console.WriteLine("Validation Error Line Position: {0}",              e.Exception.LinePosition);      Console.WriteLine("Validation Error Source: {0}",              e.Exception.Source);      Console.WriteLine("Validation Error Source Schema: {0}",              e.Exception.SourceSchemaObject);      Console.WriteLine("Validation Error Source Uri: {0}",              e.Exception.SourceUri);      Console.WriteLine("Validation Error thrown from: {0}",              e.Exception.TargetSite);      Console.WriteLine("Validation Error callstack: {0}",              e.Exception.StackTrace);  }  } 

Discussion

The Solution illustrates how to use the XmlReader to validate the book.xml document against a book.xsd XSD definition file. DTDs were the original way to specify the structure of an XML document, but it has become more common to use XSD since it reached W3C Recommendation status in May 2001. XDR was a predecessor of XSD 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 XmlReader to hold your XSD (book.xsd). Add it to the XmlSchemaSet (Schemas property) on the XmlReaderSettings object settings:

 // Wire up handler to get any validation errors.  settings.ValidationEventHandler += settings_ValidationEventHandler; // Set the validation type to schema. settings.ValidationType = ValidationType.Schema; // Add book.xsd. settings.Schemas.Add(null, XmlReader.Create(@"..\..\Book.xsd")); 

The preceding code also hooks up the schema-collection event handler for validation errors to the settings_ValidationEventHandler function. It also sets the ValidationType to Schema. Setting XmlReaderSettings.ValidationType to ValidationType. Schema tells the XmlReader 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.


The settings_ValidationEventHandler function then examines the ValidationEventArgs object passed when a validation error occurs and writes the pertinent information to the console:

 private static void settings_ValidationEventHandler(object sender,                                 ValidationEventArgs e) {     Console.WriteLine("Validation Error Message: {0}", e.Message);     Console.WriteLine("Validation Error Severity: {0}", e.Severity);     if (e.Exception != null)     {         Console.WriteLine("Validation Error Line Number: {0}",                  e.Exception.LineNumber);          Console.WriteLine("Validation Error Line Position: {0}",                  e.Exception.LinePosition);          Console.WriteLine("Validation Error Source: {0}",                  e.Exception.Source);          Console.WriteLine("Validation Error Source Schema: {0}",                  e.Exception.SourceSchemaObject);          Console.WriteLine("Validation Error Source Uri: {0}",                  e.Exception.SourceUri);         Console.WriteLine("Validation Error thrown from: {0}",                 e.Exception.TargetSite);         Console.WriteLine("Validation Error callstack: {0}",                 e.Exception.StackTrace);     } } 

Once you have the schema collection, create an XmlReader to load the BookBad.xml file:

 // Open the book.xml file. using(XmlReader reader = XmlReader.Create(@"..\..\BookBad.xml", settings)) 

You then proceed to roll over the XML document and write out the elements and attributes:

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

The BookBad.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 and Synchronization</Chapter>     <Chapter>Numbers and Enumerations</Chapter>     <BadElement>I don't belong here</BadElement>     <Chapter>Strings and Characters</Chapter>     <Chapter>Classes And Structures</Chapter>     <Chapter>Collections</Chapter>     <Chapter>XML</Chapter>     <Chapter>Delegates, Events, and Anonymous Methods</Chapter>     <Chapter>Diagnostics</Chapter>     <Chapter>Toolbox</Chapter>     <Chapter>Unsafe Code</Chapter>     <Chapter>Regular Expressions</Chapter>     <Chapter>Generics</Chapter>     <Chapter>Iterators and Partial Types</Chapter>     <Chapter>Exception Handling</Chapter>     <Chapter>Web</Chapter>     <Chapter>Networking</Chapter> </Book> 

The book.xsd file contains the following:

 <?xml version="1.0" ?> <xs:schema  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> 

When this is run, the following output is generated, showing the validation failure occurring on BadElement:

 <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 and Synchronization</Chapter> <Chapter>Numbers and Enumerations</Chapter> Validation Error Message: The element 'Book' in namespace 'http://tempuri.org/Book. xsd' has invalid child element 'BadElement' in namespace 'http://tempuri.org/Book. xsd'. List of possible elements expected: 'Chapter' in namespace 'http://tempuri.org/ Book.xsd'. Validation Error Severity: Error Validation Error Line Number: 9 Validation Error Line Position: 6 Validation Error Source: Validation Error Source Schema: Validation Error Source Uri: file:///C:/PRJ32/Book_2_0/C%23Cookbook2/Code/ CSharpRecipes/BookBad.xml Validation Error thrown from: Validation Error callstack: <BadElement>I don't belong here</BadElement> <Chapter>Strings and Characters</Chapter> <Chapter>Classes And Structures</Chapter> <Chapter>Collections</Chapter> <Chapter>XML</Chapter> <Chapter>Delegates, Events, and Anonymous Methods</Chapter> <Chapter>Diagnostics</Chapter> <Chapter>Toolbox</Chapter> <Chapter>Unsafe Code</Chapter> <Chapter>Regular Expressions</Chapter> <Chapter>Generics</Chapter> <Chapter>Iterators and Partial Types</Chapter> <Chapter>Exception Handling</Chapter> <Chapter>Web</Chapter> <Chapter>Networking</Chapter> </Book> 

See Also

See the "XmlReader Class," "XmlSchemaSet Class," "ValidationEventHandler Class," "ValidationType Enumeration," and "XmlReaderSettings Class" topics in the MSDN documentation.



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net