Click here to Skip to main content
Click here to Skip to main content

C# - XML Schema Validator

By , 12 Nov 2004
 

Introduction

Have you ever worked on a project utilizing Web Services, XML, and Schemas? Then you probably have needed to ensure the validity of the XML being passed to the Web Service against the Schema. This article shows how to use .NET's XmlValidatingReader to validate XML with a schema.

Using the code

  1. Create the XmlSchemaValidator class.
  2. Create the XML Schema.
  3. Create a WebService and add the ValidateXML method.

Note: All of the code is available via the downloadable zip file.

XmlSchemaValidator Class

The XmlSchemaValidator class contains an overloaded publicly available method ValidXmlDoc. This method allows the caller to pass in either a string of XML, an XmlDocument, or a StringReader of xml. The other parameters are the namespace and URI of the schema used to validate the XML. The method returns a boolean value, true if the XML is valid, false if the XML is invalid. There is also a publicly available string "ValidationError" that contains the validation error.

using System;
using System.Xml;
using System.Xml.Schema;
using System.IO;


namespace YourNameSpace.GoesHere
{
    /// <SUMMARY>
    /// This class validates an xml string or xml document against an xml
        /// schema.
    /// It has public methods that return a boolean value depending on 
        /// the validation
    /// of the xml.
    /// </SUMMARY>
    public class XmlSchemaValidator
    {
        private bool isValidXml = true;
        private string validationError = "";

        /// <SUMMARY>
        /// Empty Constructor.
        /// </SUMMARY>
        public XmlSchemaValidator()
        {
            
        }

        /// <SUMMARY>
        /// Public get/set access to the validation error.
        /// </SUMMARY>
        public String ValidationError
        {
            get
            {
                return "<VALIDATIONERROR>" + this.validationError 
                       + "</VALIDATIONERROR>";
            }
            set
            {
                this.validationError = value;
            }
        }

        /// <SUMMARY>
        /// Public get access to the isValidXml attribute.
        /// </SUMMARY>
        public bool IsValidXml
        {
            get
            {
                return this.isValidXml;
            }
        }

        /// <SUMMARY>
        /// This method is invoked when the XML does not match
        /// the XML Schema.
        /// </SUMMARY>
        /// <PARAM name="sender"></PARAM>
        /// <PARAM name="args"></PARAM>
        private void ValidationCallBack(object sender, 
                                   ValidationEventArgs args)
        {
            // The xml does not match the schema.
            isValidXml = false;
            this.ValidationError = args.Message;
        }  


        /// <SUMMARY>
        /// This method validates an xml string against an xml schema.
        /// </SUMMARY>
        /// <PARAM name="xml">XML string</PARAM>
        /// <PARAM name="schemaNamespace">XML Schema Namespace</PARAM>
        /// <PARAM name="schemaUri">XML Schema Uri</PARAM>
        /// <RETURNS>bool</RETURNS>
        public bool ValidXmlDoc(string xml, 
               string schemaNamespace, string schemaUri)
        {
          try
          {
               // Is the xml string valid?
               if(xml == null || xml.Length <  1)
               {
                   return false;
               }

               StringReader srXml = new StringReader(xml);
               return ValidXmlDoc(srXml, schemaNamespace, schemaUri);
          }
          catch(Exception ex)
          {
              this.ValidationError = ex.Message;
              return false;
          }
        }

        /// <SUMMARY>
        /// This method validates an xml document against an xml 
                /// schema.
        public bool ValidXmlDoc(XmlDocument xml, 
               string schemaNamespace, string schemaUri)
        {
            try
            {
                // Is the xml object valid?
                if(xml == null)
                {
                    return false;
                }

                // Create a new string writer.
                StringWriter sw = new StringWriter();
                // Set the string writer as the text writer 
                                // to write to.
                XmlTextWriter xw = new XmlTextWriter(sw);
                // Write to the text writer.
                xml.WriteTo(xw);
                // Get 
                string strXml = sw.ToString();

                StringReader srXml = new StringReader(strXml);

                return ValidXmlDoc(srXml, schemaNamespace, schemaUri);
            }
            catch(Exception ex)
            {
                this.ValidationError = ex.Message;
                return false;
            }
        }

        /// <SUMMARY>
        /// This method validates an xml string against an xml schema.
        /// </SUMMARY>
        /// <PARAM name="xml">StringReader containing xml</PARAM>
        /// <PARAM name="schemaNamespace">XML Schema Namespace</PARAM>
        /// <PARAM name="schemaUri">XML Schema Uri</PARAM>
        /// <RETURNS>bool</RETURNS>
        public bool ValidXmlDoc(StringReader xml, 
               string schemaNamespace, string schemaUri)
        {
            // Continue?
            if(xml == null || schemaNamespace == null || schemaUri == null)
            {
                return false;
            }

            isValidXml = true;
            XmlValidatingReader vr;
            XmlTextReader tr;
            XmlSchemaCollection schemaCol = new XmlSchemaCollection();
            schemaCol.Add(schemaNamespace, schemaUri);

            try 
            { 
                // Read the xml.
                tr = new XmlTextReader(xml);
                // Create the validator.
                vr = new XmlValidatingReader(tr);
                // Set the validation tyep.
                vr.ValidationType = ValidationType.Auto;
                // Add the schema.
                if(schemaCol != null)
                {
                    vr.Schemas.Add(schemaCol);
                }
                // Set the validation event handler.
                vr.ValidationEventHandler += 
                   new ValidationEventHandler(ValidationCallBack);
                // Read the xml schema.
                while(vr.Read()) 
                { 
                } 

                vr.Close(); 

                return isValidXml;
            } 
            catch(Exception ex) 
            { 
                this.ValidationError = ex.Message;
                return false; 
            } 
            finally
            {
                // Clean up...
                vr = null;
                tr = null;
            }
        }
    }
}

XmlSchema Example

The following code is an example Schema file used to validate the example XML:

<xs:schema id="XSDSchemaTest"
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  elementFormDefault="qualified" 
  attributeFormDefault="unqualified"
>

 <xs:simpleType name="FamilyMemberType">
  <xs:restriction base="xs:string">
   <xs:enumeration value="384" />
   <xs:enumeration value="385" />
   <xs:enumeration value="386" />
   <xs:enumeration value="" />
  </xs:restriction>        
 </xs:simpleType>

   <xs:element name="Answer">
     <xs:complexType>
    <xs:sequence>
      <xs:element name="ShortDesc" type="FamilyMemberType" />
      <xs:element name="AnswerValue" type="xs:int" />
     </xs:sequence>
      </xs:complexType>
     </xs:element>
</xs:schema>

XML Example

Example XML validated against the schema:

<Answer>
    <ShortDesc>385</ShortDesc> 
    <AnswerValue>1</AnswerValue> 
</Answer>

WebService Example

The WebService has a publicly available method that validates the XML. This method provides an example to one of the many ways the validator object may be used. Remember, there are three overloads to the ValidXmlDoc method.

[WebMethod]
public string ValidateXml(string xml)
{
    XmlSchemaValidator validator = new XmlSchemaValidator();

    string retVal = "<VALIDXML>" + 
           validator.ValidXmlDoc(xml, "", 
           Server.MapPath("XSDSchemaTest.xsd")).ToString() + 
           "</VALIDXML>";

    if(!validator.IsValidXml)
    {
        retVal = retVal + validator.ValidationError;
    }

    return retVal;
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Kenny Young
United States United States
Member
Ken currently works as the Director of Software Engineering at the Pediatrics Epidemiology Center at the University of South Florida. He is involved in the architecture and design on numerous clinical trial projects. Some of the project include:
 
1. Rare Diseases Clinical Research Network
2. TrialNet - Diabetes
3. Teddy - Diabetes
4. CCOP - Cancer
5. AIDA - Diabetes

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questionclass throws exceptionmembersaurabh19880111 Feb '13 - 0:05 
ProtocolManager.WebApp.PMWebService”
GeneralMy vote of 5 [modified]memberVMAtm18 Sep '12 - 0:09 
Very interesting and helpful article. Thank you!
 
But some of your code is now depcrecated (such as ValidationType.Auto)

-- modified 18 Sep '12 - 6:19.
QuestionWhat can I do?memberjinda_tra@hotmail.com9 Nov '06 - 17:33 
I created web site on ASP.NET Web Service. I created method access database and query data return DataSet type.
 
// Source code of web service
[WebMethod]
public DataSet AddEvent()
{
System.Data.SqlClient.SqlConnection sqlConnection1;
System.Data.SqlClient.SqlDataAdapter daEvents;
DataSet ds;
 
sqlConnection1 = new System.Data.SqlClient.SqlConnection();
sqlConnection1.ConnectionString = ConfigurationManager.ConnectionStrings["TestServer"].ConnectionString;
sqlConnection1.Open();
MessageBox.Show("Connect Sucess");

daEvents = new System.Data.SqlClient.SqlDataAdapter("Select * From SC_History", sqlConnection1);
ds = (DataSet)Application["ds"];
ds.Tables["Events"].Clear();
daEvents.Fill(ds, "Events");
Application.Lock();
Application["ds"] = ds;
Application.UnLock();
 
sqlConnection1.Close();
return ds;
}
 

After that, I used wiht Windows Application and it show error. -->
 
System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.ArgumentException: Keyword not supported: '"data source'.
at System.Data.Common.DbConnectionOptions.ParseInternal(Hashtable parsetable, String connectionString, Boolean buildChain, Hashtable synonyms, Boolean firstKey)
at System.Data.Common.DbConnectionOptions..ctor(String connectionString, Hashtable synonyms, Boolean useOdbcRules)
at System.Data.SqlClient.SqlConnectionString..ctor(String connectionString)
at System.Data.SqlClient.SqlConnectionFactory.CreateConnectionOptions(String connectionString, DbConnectionOptions previous)
at System.Data.ProviderBase.DbConnectionFactory.GetConnectionPoolGroup(String connectionString, DbConnectionPoolGroupOptions poolOptions, DbConnectionOptions& userConnectionOptions)
at System.Data.SqlClient.SqlConnection.ConnectionString_Set(String value)
at System.Data.SqlClient.SqlConnection.set_ConnectionString(String value)
at Service.AddEvent()
--- End of inner exception stack trace ---
 

How I do it?
 
Thank you very.

Generalexception on using xmlschemavalidator class [modified]memberninja260523 Aug '06 - 1:36 
I get the following exception on using the xmlschemavalidator class
 
"The attribute targetNamespace does not match the designated namespace URI. An error occurred at file:///C:/Inetpub/wwwroot/SamrtCardTest/CCR_20051109.xsd.
 
The first two lines of xml are:
<?xml version="1.0" encoding="utf-8"?>
<ContinuityOfCareRecord xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:astm-org:CCR">
 
and the first two lines of xsd are:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="urn:astm-org:CCR" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ccr="urn:astm-org:CCR" targetNamespace="urn:astm-org:CCR" elementFormDefault="qualified" attributeFormDefault="unqualified">
 
Is there a problem with xml?
 
Thanks and Regards
Nitin
 

 
-- modified at 7:38 Wednesday 23rd August, 2006
GeneralRe: exception on using xmlschemavalidator classmemberDapo Onawole17 Apr '07 - 12:53 
Pls can u kindly send ur ccr xsd schema file. I need it and where can I get the most recent ccr schema file. Searched all over the internet with no success.
QuestionValidation failed unexpectantly???memberRichard Beacroft5 Jan '06 - 1:20 
Unfortunately, I always receive an error:


False
The 'http://tempuri.org/xmlvalid_test.xsd:AnswerValue' element is not declared. An error occurred at , (1, 81).

 
XSD:



















 
XML:

385
1

 
Any ideas where I'm going wrong???
 
Regards,
 
Rik
Questionread xml schemasussAnonymous27 Sep '05 - 2:55 
Suppose I have xml schema file next to my c# class, how do I read in the xml schema file from c# class?
 
Thanks,
Generalmultiple namespacesussAnonymous8 Jun '05 - 22:15 
What if I have multiple namespaces?
 

="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
GeneralHelp!sussAnonymous7 Jun '05 - 23:31 
What do I need to put into string schemaNamespace?
GeneralRe: Help!memberKenny Young15 Jun '05 - 5:05 
The namespace URI associated with the schema. For XML Schema definition language (XSD) schemas, this will typically be the targetNamespace. You can also pass an empty string like I did in the example.
 
Please read the MSDN Article on the XmlSchemaCollection.Add Method (String, String):
Generalusing schemaLocation attributememberBigDave6423 Mar '05 - 14:43 
Hi,
 
Excellent example. Thanks for posting it.
 
I would like to overload ValidXmlDoc to accept just the XML doc, then get the schema using the schemaLocation attribute inside the XML file, instead of as an argument. For example, if my XML root looks like this:
 

 
Can you demonstrate how this would be done? Thanks.
 
- Dave
GeneralRe: using schemaLocation attributesussKenny Young24 Mar '05 - 3:48 
public bool ValidXmlDoc(XmlDocument xml)
{
try
{
// Is the xml object valid?
if(xml == null)
{
return false;
}
 
string schemaUri = "";

XmlNode root = xml.DocumentElement;
XmlNamespaceManager xnsManager = new XmlNamespaceManager(xml.NameTable);
xnsManager.AddNamespace( "xsi", "http://www.w3.org/2001/XMLSchema-instance");
XmlNode schemaLoc = root.SelectSingleNode("@xsi:noNamespaceSchemaLocation", xnsManager);

if(schemaLoc != null)
{
schemaUri = schemaLoc.InnerText;
}
 
// Create a new string writer.
StringWriter sw = new StringWriter();
// Set the string writer as the text writer
// to write to.
XmlTextWriter xw = new XmlTextWriter(sw);
// Write to the text writer.
xml.WriteTo(xw);
// Get
string strXml = sw.ToString();
 
StringReader srXml = new StringReader(strXml);
 
return ValidXmlDoc(srXml, "", schemaUri);
}
catch(Exception ex)
{
this.ValidationError = ex.Message;
return false;
}
}
GeneralRe: using schemaLocation attributememberBigDave6431 Mar '05 - 9:23 
Great!   Thanks.
 
One more question:
 
What if the schema referenced in the xml document includes another schema, like so:
 
<xs:include xsi:noNamespaceSchemaLocation="my_types.xsd"/>
 
Your code works great when everything is contained in a single schema, but it breaks when I split the schema into multiple schemas.   How can I make sure that all relevant schemas are made available to the validator, while still only providing the xml document as an argument.   I also want to stay away from hardcoding schemas into the code.   What do you think?
 
Thanks again!
GeneralRe: using schemaLocation attributememberKenny Young1 Apr '05 - 3:39 
I would recommend looping through the number of schemas and pass the xmldoc for each schema. If any of the validations return false, then your xmldoc is not valid.
 

GeneralRe: using schemaLocation attributememberSixPeak9 Oct '08 - 15:56 
未能创建类型“ProtocolManager.WebApp.PMWebService”。
GeneralThis method never parses the xml documentmemberlemuel5516 Jan '05 - 3:13 

Look at your code for the xml.doc check method as shown below:
You check the xml document for null and after that it is never used in this method again. Am I missing something or is something left out?
 
 ///<SUMMARY>
        /// This method validates an xml document against an xml 
                /// schema.
        public bool ValidXmlDoc(XmlDocument xml, 
               string schemaNamespace, string schemaUri)
        {
            try
            {
                // Is the xml object valid?
checked here  	if(xml == null)
                {
                    return false;
                }
 
                // Create a new string writer.
                StringWriter sw = new StringWriter();
                // Set the string writer as the text writer 
                                // to write to.
                XmlTextWriter xw = new XmlTextWriter(sw);
                // Write to the text writer.
                xml.WriteTo(xw);
                // Get 
                string strXml = sw.ToString();
 
                StringReader srXml = new StringReader(strXml);
 
                return ValidXmlDoc(srXml, schemaNamespace, schemaUri);
            }
            catch(Exception ex)
            {
                this.ValidationError = ex.Message;
                return false;
            }
        }

 
Lemuel Kinney
lemuelk@cfl.rr.com
GeneralRe: This method never parses the xml documentmemberKenny Young18 Jan '05 - 6:06 
The ValidXmlDoc method has several overloaded methods. The method you are referreing to, first ensures that the xml is not null, then it writes the xml document to a stringreader and calls the ValidXmlDoc method that does the actual work public bool ValidXmlDoc(StringReader xml,
string schemaNamespace, string schemaUri).

If you notice at the end of the method your are looking at, the last line before the catch statement is:

return ValidXmlDoc(srXml, schemaNamespace, schemaUri);



For further help, if you run the downloadable solution, you can put a break point in the method of concern, and step through the code.


Hope this helps...
 
Kenny Young

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 12 Nov 2004
Article Copyright 2004 by Kenny Young
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid