Recently I was tasked with loading XML over HTTP to integrate my employer with a customers website. The customer provided me with several XSD and DTD files to validate my requests and resulst. Deciding that the DTD was older technology I focused on the XSD. After a quick search on XMLPitstop I located a C# example that did the trick and decided to upload my test-app which was built in our company standard programming language (VB). This app demonstrates how to load an XML file and validate it against an XSD file. I also included a small rant about the WithEvents statement as it relates to local variables. Hopefully somebody will tell me that I am an idiot and have this WithEvents syntax all wrong because as I see it you must move your local variables out of scope and make them member variables in your class if you intend to handle events with them. This will certainly cause your class to be polluted with out-of-scope variables that are only used in a single function in many cases. This is also demonstrated in the code below. Enjoy!
Public Class Form1
Private m_ValidationErrors As String = ""
<<<< WINDOWS FORM DESIGNER GENERATED CODE WAS REMOVED >>>>
Private WithEvents m_xvrSchema As XmlValidatingReader 'See RANT below!
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Set File Paths
Dim xmlPath As String = "c:\test.xml"
Dim xsdPath As String = "c:\test.xsd"
' Open the XML file.
Dim xmlDoc As New XmlDocument
' Validate the XML document
Dim strErrors As String = ValidateXML(xmlDoc, xsdPath)
Public Function ValidateXML(ByVal xmlDoc As XmlDocument, ByVal xsdPath As String) As String
'a) We are using the XMLValidatingReader to validate the xml object against the schema.
' You may note that we are passing into it the actual xml string contained in our XML Object
m_xvrSchema = New XmlValidatingReader(xmlDoc.OuterXml, XmlNodeType.Document, Nothing)
'b) We are using the XMLTextReader object to create an instance of our Schema.
Dim xtrSchema As New XmlTextReader(xsdPath)
'c) We are creating a Schemas collection to hold the schemas that we wish to test against our xml
Dim xscSchema As New XmlSchemaCollection
'd) We now add our schema object (defined in step b) to our schemas collection
'e) In this step, we add the schema collection to our ValidatingTextReader object
'f) Add validation event handler
' Note that this Validation handler will be used to do "something" whenever a validation error occurs.
' In short, it allows us to specify a method to call when an error occurs. In the case of this function,
' we are storing the error message into a variable named "ValidationErrors"
m_xvrSchema.ValidationType = ValidationType.Schema
' HERE IS THE RANT!!!
' In VB.NET you cannot declare local variables using the WithEvents modifier. That means
' that all variable definitions used in your program that must handle events must be declared
' as member variables even if the scope is local to your function only. This can result in
' your class being polluted with mebmer variables that are out of scope. In C# I would declare
' the variable locally in this function and wire up the handler using the (event += handler)
' construct seen below:
' m_xvrSchema.ValidationEventHandler += New ValidationEventHandler(ValidationHandler)
'g) Iterate through all of the Nodes in our XML Document, storing any errors in the "ValidationErrors" variable
'Nothing to do here - just keep reading the data...
' h) Return any errors generated as a result of this validation (as mentioned, all errors stored in the "ValidationErrors" variable)
Public Sub ValidationHandler(ByVal sender As Object, ByVal args As ValidationEventArgs) Handles m_xvrSchema.ValidationEventHandler
m_ValidationErrors = m_ValidationErrors + args.Message + "\r\n"