.NET 2.0 deprecated the XmlValidatingReader class, proposing that you use the XmlReader class
and the new XmlReaderSettings class
instead.
Microsoft also introduced a slew of bug fixes to the validation logic – including
the ability to correctly process Xsd import and include directives.
I was trying to test a fairly complex schema recently with BizUnit – a schema which
has a lot of includes.
And BizUnit would consistently throw an exception.
Looking through the BizUnit source code, I noticed that the XmlValidatingReader was
being used:
XmlDocument doc
= new XmlDocument();
XmlTextReader trData
= new XmlTextReader(
data );
XmlValidatingReader vr = new XmlValidatingReader(trData);
// If schema was specified use it to validate against…
if ( null != xmlSchemaPath
)
{
MemoryStream xsdSchema = StreamHelper.LoadFileToStream(xmlSchemaPath);
XmlTextReader trSchema = new XmlTextReader(
xsdSchema );
XmlSchemaCollection xsc = new XmlSchemaCollection();
if ( null !=
ns )
{
xsc.Add( ns, trSchema );
vr.Schemas.Add(xsc);
}
doc.Load(vr);
}
I’ve raised an issue on the BizUnit CodePlex site for this, but in the meantime I
updated the XmlValidationStep.cs source file to this:
XmlDocument doc
= new XmlDocument();
XmlTextReader trData
= new XmlTextReader(data);
// If schema was specified use it
to vaidate against…
if (null != xmlSchemaPath)
{
FileInfo fi = new FileInfo(xmlSchemaPath);
// Store the current diretcory whilst we
temporarily change it
string currentDirectory = Environment.CurrentDirectory;
// Change the current directory to the schema
location so that
// any relative imports/includes in the schema will work correctly
Environment.CurrentDirectory = fi.DirectoryName;
MemoryStream xsdSchema = StreamHelper.LoadFileToStream(xmlSchemaPath);
XmlTextReader trSchema = new XmlTextReader(xsdSchema);
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
if (null !=
ns)
{
settings.Schemas.Add(ns, trSchema);
}
else
{
settings.Schemas.Add(null,
trSchema);
}
XmlReader vr = XmlReader.Create(trData,
settings);
while (vr.Read()) { }
// Reset the current directory
Environment.CurrentDirectory = currentDirectory;
}
Note: Interestingly, the BizTalk XmlValidator pipeline component also uses
the .NET 1.0 classes…
I also made two other changes:
if ( 0 != nodeValue.CompareTo( checkNode.InnerText )
)
If the xPath statement you’re using returns no nodes (usually because you typed it
in wrong!), then this will throw an exception.
Your test will fail (as expected) but instead of a useful error, you’ll get an “object
reference not set to an instance of an object” error…
XmlNode checkNode = null;
try
{
checkNode = doc.SelectSingleNode(xpathExp);
}
catch { }
if (checkNode != null)
{
if (0 != nodeValue.CompareTo(checkNode.InnerText))
{
throw new ApplicationException(string.Format(“XmlValidationStepEnhanced
failed, compare {0} != {1}, xpath query used: {2}”, nodeValue, checkNode.InnerText,
xpathExp));
}
}
else
{
XPathNavigator xpn = doc.CreateNavigator();
object result = xpn.Evaluate(xpathExp);
string checkValue = null;
if (result.GetType().Name == “XPathSelectionIterator“)
{
XPathNodeIterator xpi
= result as XPathNodeIterator;
xpi.MoveNext();
if (null !=
xpi)
{
checkValue = xpi.Current.ToString();
}
}
else
{
checkValue = result.ToString();
}
if (0
!= nodeValue.CompareTo(checkValue))
Works for me!
Not sure if I should do this (!) but here’s a version of my updated XmlValidationStep.cs file.
If you wish you can grab the source file and compile your own version of the core
BizUnit assembly should you need this functionality as well.