Click here to Skip to main content
Email Password   helpLost your password?

Introduction

I had a need to validate an XML file against a schema file (XSD) in VB.NET. So I wrote a simple app that could do this validation. While I was at it I decided it might be nice to validate the schema file all by itself. The basic core functions could be reused in your code to validate XML files against a schema, or just validate the schema file by itself. So I spent an hour or two to put this SimpleXMLValidator together. Most of the code can be found in partial form in the Visual Studio help files.

Background

I started working on a project where I had the option to use a flat file fixed length format or XML file with a schema. Since there was the need to verify that we didn't lose any data on the transfer of the file to our system, I decided on the XML file with schema (not that I would ever choose a flat file over XML). I figured this would also help catch any changes to the XML format. You know how vendors change their format and don't tell you. Then it is a big guessing game to what changed. This little app helps you identify what is wrong, so you know where to look for, to fix the problem.

The code

There are two functions and one sub that do the real work. Each of the functions calls a delegate (which is the one sub) if a validation error occurs. Note that the signature of the sub is important, (that is, the input variables to the procedure must match the delegate signature). All I am really doing in this sub is setting a variable to mark the file as failed validation and displaying the error in a RichTextBox. Here's the code:

'vb.net

Private Sub ValidationCallBack(ByVal sender As Object, ByVal args As _
    ValidationEventArgs)
        'Display the validation error.  This is only called on error

        m_Success = False 'Validation failed

        writertbox("Validation error: " + args.Message)
End Sub
//C#

private void ValidationCallBack(Object sender, ValidationEventArgs args)
    {
       //Display the validation error.  This is only called on error

       m_Success = false; //Validation failed

       writertbox("Validation error: " + args.Message);
    }

Next we have the XML validation code. Really the only important prerequisite is that the XML file should point to the correct schema file (XSD) inside the XML file on the XSI tag.

Here is an example:

<?xml version="1.0" encoding="utf-8"?>
<ROOTElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:noNamespaceSchemaLocation="yourschema.xsd">

Here is the code for the XML validation function:

'vb.net

Private Function validatexml(ByVal infile As String) As Boolean
        'First we create the xmltextreader

        Dim xmlr As New XmlTextReader(infile)
        'We pass the xmltextreader into the xmlvalidatingreader

        'This will validate the xml doc with the schema file

        'NOTE the xml file it self points to the schema file

        Dim xmlvread As New XmlValidatingReader(xmlr)

        ' Set the validation event handler

        AddHandler xmlvread.ValidationEventHandler, _
        AddressOf ValidationCallBack
        m_Success = True 'make sure to reset the success var


        ' Read XML data

        While (xmlvread.Read)
        End While
        'Close the reader.

        xmlvread.Close()

        'The validationeventhandler is the only thing that would 

        'set m_Success to false

        Return m_Success
End Function
//C#

private bool validateXml(String infile)
{
    //First we create the xmltextreader

    XmlTextReader xmlr = new XmlTextReader(infile);
    //We pass the xmltextreader into the xmlvalidatingreader

    //This will validate the xml doc with the schema file

    //NOTE the xml file it self points to the schema file

    XmlValidatingReader xmlvread = new XmlValidatingReader(xmlr);

    // Set the validation event handler

    xmlvread.ValidationEventHandler += 
        new ValidationEventHandler (ValidationCallBack);
    m_Success = true; //make sure to reset the success var


    // Read XML data

    while (xmlvread.Read()){}

    //Close the reader.

    xmlvread.Close();

    //The validationeventhandler is the only thing that would set 

    //m_Success to false

    return m_Success;
}

Finally, we have the code to validate the schema (XSD) file directly. As mentioned before, this function has a callback to the same on validation event as the XML validation function did.

Here is the code:

'vb.net

Private Function validateSchema(ByVal infilename As String) As Boolean
        'this function will validate the schema file (xsd)

        Dim sr As StreamReader
        Dim myschema As XmlSchema
        m_Success = True 'make sure to reset the success var

        Try
            sr = New StreamReader(infilename)
            myschema = XmlSchema.Read(sr, AddressOf ValidationCallBack)
            'This compile statement is what ususally catches the errors

            myschema.Compile(AddressOf ValidationCallBack)

        Finally
            sr.Close()
        End Try
        Return m_Success
End Function
//C#

private bool validateSchema(String infilename)
{
    //this function will validate the schema file (xsd)

    XmlSchema myschema; 
    m_Success = true; //make sure to reset the success var

    StreamReader sr = new StreamReader(infilename);
    try
    {
    myschema = XmlSchema.Read(sr, 
        new ValidationEventHandler (ValidationCallBack));
    //This compile statement is what ususally catches the errors

    myschema.Compile(new ValidationEventHandler (ValidationCallBack));
    }                            
        finally
    {
        sr.Close();
    }
    return m_Success;
}

Conclusion

Well, that is it. Not really a lot to it. I am sure many of you already knew how to do this. I kind of wish you had published an article, it would have saved me some time. Still the learning process is always enjoyable and never ends.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralMy vote of 1
Muris Hadzimejlic
2:52 14 Dec '09  
doesn't do what expected
General[My vote of 2] poor article
Donsw
7:28 24 Aug '09  
although you have the source code you have no xml, xsd samples. In trying my own they fail for no given reason. It would be nice to see one that you have that works. also you have no error catching in the application.

cheers,
Donsw
My Recent Article : Backup of Data files - Full and Incremental

GeneralRe: [My vote of 2] poor article
kubben
7:34 24 Aug '09  
I would guess that you are using .net 2.0 or above. This article was written a long time ago for .net 1.1. I have a post below that has .net 2.0 code, that I would guess would work better for you.

Simple code to validate an XML file against a schema file (XSD)[^]

ben
GeneralMy vote of 1
Paresh Gheewala
20:58 2 Dec '08  
N/A
GeneralXML Validation.
Member 1557199
0:53 22 May '08  
Hi,

Is there any way to find the node that was being validated.
I want to find the complete XPath of the validating node, for traceability.

Waiting for your early...Its an urgent pls.

Thanks,
Kumar. V
GeneralRe: XML Validation.
kubben
2:01 22 May '08  
I don't know any way of doing it. There may be a way. The issue is that the schema validation is just a method call. So you don't really get to step through the process. You just call the method. Normally if you get a schma validation error it should tell you what node, but I am guessing you are looking for something else. Sorry I couldn't be more helpful.

Ben
GeneralHow to specify schema namespace for xml file ?
Tejas G. Patel
9:06 4 Dec '07  
Hi,
I am validating XML file against XSD file.but i m creating xml file at runtime so i m not being able to specify namespace for my xml file which is needed by xml file to be validated by the xsd's schema specification.
I know its like (xmlns) tag.

help me ASAP.

thanx in advance
GeneralRe: How to specify schema namespace for xml file ?
kubben
2:50 12 Jan '08  
Sorry I am just responding now. I didn't get the notification that you posted a question.

Anyway, if you are using .net 2.0 there are some posibilities. If you are using .net 1.1 there isn't a great way of doing it.

Here is a sample of some simple C# code that works in .net 2.0:

private void Form1_Load(object sender, EventArgs e)
{
XmlDocument tmpDoc = new XmlDocument();
tmpDoc.Load(@"Sample.xml");
tmpDoc.Schemas.Add(null, @"Sample.xsd");
ValidationEventHandler eventHandler = new ValidationEventHandler(ValidationEventHandler);

tmpDoc.Validate(eventHandler);

}

static void ValidationEventHandler(object sender, ValidationEventArgs e)
{
switch (e.Severity)
{
case XmlSeverityType.Error:
MessageBox.Show("Error: {0}"+ e.Message);
break;
case XmlSeverityType.Warning:
MessageBox.Show("Warning {0}"+ e.Message);
break;
}

}

You just need to take the code out of the form load method and put it where ever you need it. Also change the hard coded Sample.xml and Sample.xsd to your file names.


In your case instead of loading an existing xml doc you can add your dynamic xml to the xml doc.

Ben
Generalminoccurs validation
RHBKV
19:26 21 Nov '07  
suppose if i specify minouccurs = 1 for all nodes in xsd and missed (eg:any three nodes continously) in xml input, validating reader showing only one error " The element 'PrimaryHeader' has invalid child element 'EmpName'. Expected 'empID'. An error occurred at , (1, 387).". but it is not showing the errors for remaining 2 elements. Reader skipped to next valid node.
can you help me how to capture all errors like the above error
Thanks
GeneralRe: minoccurs validation
kubben
2:26 22 Nov '07  
I was also frustrated with this functionality, unfortunately I didn't find a way around it. It appears that is just how the validatingreader works. Now perhaps I missed a setting that you can pass in or something. Sorry I don't know how to help you in this case.

Ben
GeneralSome .net 2.0 code... [modified]
kubben
8:14 22 May '06  
Some people have asked about code that would work in .net 2.0. Here is a sample of some simple C# code that works in .net 2.0:

private void Form1_Load(object sender, EventArgs e)
{
XmlDocument tmpDoc = new XmlDocument();
tmpDoc.Load(@"Sample.xml");
tmpDoc.Schemas.Add(null, @"Sample.xsd");
ValidationEventHandler eventHandler = new ValidationEventHandler(ValidationEventHandler);

tmpDoc.Validate(eventHandler);

}

static void ValidationEventHandler(object sender, ValidationEventArgs e)
{
switch (e.Severity)
{
case XmlSeverityType.Error:
MessageBox.Show("Error: {0}"+ e.Message);
break;
case XmlSeverityType.Warning:
MessageBox.Show("Warning {0}"+ e.Message);
break;
}

}

You just need to take the code out of the form load method and put it where ever you need it. Also change the hard coded Sample.xml and Sample.xsd to your file names.

Ben

-- modified at 14:01 Monday 22nd May, 2006
GeneralDoesn't work for me
voodoo9055
6:16 21 Mar '07  
I copied the code and nothing happens even when I rename tags and data types. I have never been able to get the xml validation stuff to work.
GeneralRe: Doesn't work for me
kubben
4:18 22 Mar '07  
Do you get error messages or something? Hard to figure out the problem without seeing your code or any error messages you are getting.

Ben
GeneralApplied XML programming for Microsft .Net by Dino Esposito
eggie5
7:50 28 May '05  
Do you have this book or something?
GeneralRe: Applied XML programming for Microsft .Net by Dino Esposito
kubben
17:22 29 May '05  
No actually I don't. I might have to find it to see if what you are saying is true. Like I mentioned in the article, all the source code for this app was more or less gotten from microsoft on-line help from visual studio. I just sort of pulled pieces and parts to make it work like I wanted it to. It is a pretty simple UI, I pretty much just slapped the basic components that I needed.
I will have to stop by Barns and Nobel or something and see what is on page 83 like you suggested in your email.

Ben
GeneralSpecifying the schema externally
The Chaos Engine
22:07 25 May '05  
Hi,

How about expanding the artile to show how to specify the schema to validate the XML against at validation time? Rather than relying on a static XSD reference.

Thanks

Oli
GeneralRe: Specifying the schema externally [modified]
kubben
9:13 22 May '06  
Well, this is coming a little late. There are actually better ways of doing this in .net 2.0, Still I had some time so here is the code so the schema doesn't need to be in the xml file:

private XmlSchemaCollection _xmlSchemaCollection = new XmlSchemaCollection();

private void Form1_Load(object sender, System.EventArgs e)
{
_xmlSchemaCollection.Add("",new XmlTextReader(@"Sample.xsd"));

XmlValidatingReader validatingReader = null;
try
{
// Read the file using the validating reader
validatingReader = new XmlValidatingReader(new XmlTextReader(@"Sample.xml"));

validatingReader.ValidationEventHandler +=new ValidationEventHandler(validatingReader_ValidationEventHandler);

validatingReader.Schemas.Add(_xmlSchemaCollection);

while (validatingReader.Read()) {}
}
catch(System.Exception ex)
{
throw new System.Exception("Exception in initial schema validation.",ex);
}
finally
{
validatingReader.Close();
}
}
//Event Handler for validation errors.
private void validatingReader_ValidationEventHandler(object sender, ValidationEventArgs e)
{

switch (e.Severity)
{
case XmlSeverityType.Warning:
MessageBox.Show(e.Message);
break;
case XmlSeverityType.Error:
MessageBox.Show(e.Exception.Message);
break;
}
}

I hope it helps. I would guess by now you already have this figured out.

Ben

-- modified at 14:13 Monday 22nd May, 2006
QuestionRe: Specifying the schema externally
thesitemaster
4:44 9 Mar '07  
To make it possible to pass a string with XSD content instead of a location I changed a single line of the code above:
Original: validatingReader = new XmlValidatingReader(new XmlTextReader(@"Sample.xml"));
New:              
validatingReader = new XmlValidatingReader(new XmlTextReader(new StringReader(xsdInput)));     
     
Besides a warning that this function is qualified as obsolete I get an error: “The targetNamespace parameter '' should be the same value as the targetNamespace 'urn:bookstore-schema' of the schema.”           

I’d like to validate a xml string against a xsd string. To make is possible to use this code for every input, I don’t want to use a hard coded target namespace, e.g. urn:bookstore-schema (just like described in post above). How can I retrieve the target namespace out of the XSD string? In stead of manipulating the string, I wonder if it is possible to do this by using the existing API.

<code>
string xmlInput
string xsdInput
XmlSchemaSet sc = new XmlSchemaSet();

sc.Add(urn:bookstore-schema), XmlReader.Create(new StringReader(xsdInput));

// Set the validation settings.
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.Schemas = sc;
settings.ValidationEventHandler += new
ValidationEventHandler(ValidationCallBack);
</code>

AnswerRe: Specifying the schema externally
kubben
4:57 9 Mar '07  
Are you able to use .net 2.0 at all? The xml schema validation stuff is a lot better in .net 2.0. It is a little limited in 1.1.

Here is a sample from MS help:
Visual Basic
Imports System
Imports System.Xml
Imports System.Xml.Schema
Imports System.IO

public class Sample

public shared sub Main()

' Create the XmlSchemaSet class.
Dim sc as XmlSchemaSet = new XmlSchemaSet()

' Add the schema to the collection.
sc.Add("urn:bookstore-schema", "books.xsd")

' Set the validation settings.
Dim settings as XmlReaderSettings = new XmlReaderSettings()
settings.ValidationType = ValidationType.Schema
settings.Schemas = sc
AddHandler settings.ValidationEventHandler, AddressOf ValidationCallBack

' Create the XmlReader object.
Dim reader as XmlReader = XmlReader.Create("booksSchemaFail.xml", settings)

' Parse the file.
while reader.Read()
end while

end sub

' Display any validation errors.
private shared sub ValidationCallBack(sender as object, e as ValidationEventArgs)
Console.WriteLine("Validation Error: {0}", e.Message)
end sub
end class


C#
using System;
using System.Xml;
using System.Xml.Schema;
using System.IO;

public class Sample {

public static void Main() {

// Create the XmlSchemaSet class.
XmlSchemaSet sc = new XmlSchemaSet();

// Add the schema to the collection.
sc.Add("urn:bookstore-schema", "books.xsd");

// Set the validation settings.
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.Schemas = sc;
settings.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);

// Create the XmlReader object.
XmlReader reader = XmlReader.Create("booksSchemaFail.xml", settings);

// Parse the file.
while (reader.Read());

}

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


NOTE that when you add the schema to the schema set you can use a xmlreader.

So there is a clear way to do it in .net 2.0

I supose if you work on it long enough you can figure out a way of doing it in 1.1

Hope that helps.
Ben


Last Updated 26 May 2005 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010