Groups | Blog | Home
all groups > dotnet xml > august 2004 >

dotnet xml : validating XML using XmlValidatingReader - XML ignoring schema


andyrich_1 NO[at]SPAM hotmail.com
8/5/2004 7:02:50 AM
I am having some trouble validating XML using the XmlValidatingReader.
I have created some xml and used the visual studio to generate the
schema. So I am confident that the xml and schema match.

The problem I am having is that the validation event fires for each
node in the xml. It seems to be completely ignoring the schema that I
have used.

I'm wondering if I need to do something extra to tell the xml which
schema to use.

Here's the code. Any help at all would be great.

Thanks
Andy


public sub Main()

Dim sSchema As String = "<?xml version='1.0'?>" & _
"<xs:schema id='MyApp'
targetNamespace='http://tempuri.org/test.xsd'
xmlns:mstns='http://tempuri.org/test.xsd'
xmlns='http://tempuri.org/test.xsd'
xmlns:xs='http://www.w3.org/2001/XMLSchema'
xmlns:msdata='urn:schemas-microsoft-com:xml-msdata'
attributeFormDefault='qualified' elementFormDefault='qualified'>" & _
"<xs:element name='MyApp'
msdata:IsDataSet='true' msdata:Locale='en-GB'
msdata:EnforceConstraints='False'>" & _
"<xs:complexType>" & _
"<xs:choice
maxOccurs='unbounded'>" & _
"<xs:element name='os'>" &
_
"<xs:complexType>" & _
"<xs:sequence>" & _
"<xs:element
name='client' minOccurs='0' maxOccurs='unbounded'>" & _
"<xs:complexType>"
& _
"<xs:attribute
name='wmp_v' form='unqualified' type='xs:string' />" & _
"<xs:attribute
name='s_v' form='unqualified' type='xs:string' />" & _
"<xs:attribute
name='file' form='unqualified' type='xs:string' />" & _

"</xs:complexType>" & _
"</xs:element>" & _
"</xs:sequence>" & _
"<xs:attribute
name='v' form='unqualified' type='xs:string' />" & _
"</xs:complexType>" & _
"</xs:element>" & _
"</xs:choice>" & _
"</xs:complexType>" & _
"</xs:element>" & _
"</xs:schema>"

Dim ValidatorReader As New Xml.XmlTextReader(New
StringReader(sSchema))
Dim ValidationSchema As New Xml.Schema.XmlSchema
Dim colSchemas As New Xml.Schema.XmlSchemaCollection

ValidationSchema.Read(ValidatorReader, AddressOf
ValidationEventHandler)
ValidationSchema.Compile(AddressOf ValidationEventHandler)
colSchemas.Add(ValidationSchema)

'XML to validate
Dim sXML As String = "<MyApp
xmlns='http://tempuri.org/test.xsd'>" & _
"<os v='xp'> <client wmp_v='9'
s_v='9' file=''/><client wmp_v='10' s_v='10' file=''/></os>" & _
"</MyApp>"
Dim InputXMLReader As New Xml.XmlTextReader(New
StringReader(sXML))
Dim xmlValidator As New
Xml.XmlValidatingReader(InputXMLReader)

xmlValidator.ValidationType = Xml.ValidationType.Schema
AddHandler xmlValidator.ValidationEventHandler, AddressOf
ValidationEventHandler

'Add schema to the validating reader
xmlValidator.Schemas.Add(colSchemas)

While xmlValidator.Read()
'Validation even is fired for evey node.
End While

Catch ex As Exception
Debug.WriteLine(ex.Message)
End Try

End Sub

Public Shared Sub ValidationEventHandler(ByVal sender As Object,
ByVal e As Xml.Schema.ValidationEventArgs)
Select Case e.Severity
Case Xml.Schema.XmlSeverityType.Error
Debug.WriteLine(e.Exception.Message)
Case Xml.Schema.XmlSeverityType.Warning
Debug.WriteLine(e.Exception.Message)
End Select

Derek Harmon
8/5/2004 10:42:56 PM
[quoted text, click to view]

Is what you're seeing a number of "element is not declared" errors?

[quoted text, click to view]

Well, let's look carefully at how ValidationSchema is being created.

: :
[quoted text, click to view]

On the first line, ValidationSchema is created as an empty schema.

On the second line, XmlSchema::Read( ) is being called to load in the
XML Schema Document contained in sSchema and _then throwing
it all away_.

On the third line, Compile( ) is happily compiling the empty schema
you created in the first line.

On the fourth line, Add( ) adds the empty schema to the collection of
schemas you later use to validate the the instance document. Of
course, since it is empty, every element encountered in the instance
document receives an "element is not declared" error.

Being an observant programmer, I'm sure your eyes bugged out when
I described what was happening on the second line, so let's go back
to that. :-)

I say "throwing it all away" because Read is a Shared Sub. Now, in
some programming languages (like C#) this is a very difficult typo to
make, because the compiler will emit an error should you call such a
static method using an instance object. However, Visual Basic is
much more forgiving, and will just assume, since ValidationSchema
IS an XmlSchema anyway, that you really wanted to call XmlSchema::
Read( ) and didn't want a diagnostic.

So, whereas from looking at the line,

ValidationSchema.Read( ValidatorReader, AddressOf veh)

you might think [where are the Cars?] the Read operation is feeding
its resulting SOM into the ValidationSchema object that you're going
to compile and add into a collection later, what is actually happening
is,

XmlSchema.Read( ValidatorReader, AddressOf veh)

XmlSchema::Read( ) returns an XmlSchema. There is no variable on
the left-hand side to receive that XmlSchema that it's read, so it just
gets thrown away.

The answer then, is to capture the XmlSchema returned by Read( ):

Dim ValidationSchema As Xml.Schema.XmlSchema ' New isn't required.
ValidationSchema = XmlSchema.Read( _
ValidatorReader, _
AddressOf ValidationEventHandler _
)
' ValidationSchema is no longer empty.


Derek Harmon

AddThis Social Bookmark Button