Xdocument.Validate Is Always Successful

XDocument.Validate is always successful

I am not sure it is possible to use the Validate method; if you use a validating XmlReader over the XDocument where ValidationFlags are set up to emit validation warnings, as in

        XDocument doc = XDocument.Load("../../XMLFile1.xml");

XmlSchemaSet schemaSet = new XmlSchemaSet();
schemaSet.Add(null, "../../XMLSchema1.xsd");

XmlReaderSettings xrs = new XmlReaderSettings();
xrs.ValidationType = ValidationType.Schema;
xrs.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
xrs.Schemas = schemaSet;
xrs.ValidationEventHandler += (o, s) => {
Console.WriteLine("{0}: {1}", s.Severity, s.Message);
};

using (XmlReader xr = XmlReader.Create(doc.CreateReader(), xrs))
{
while (xr.Read()) { }
}

then the ValidationEventHandler does emit a warning for each node it does not find schema information for. So your ValidationEventHandler could check for such warnings. But you might as well simply compare the doc.Root.Name.Namespace with the target namespace of the schemas you have before calling the Validate method.

Invalid XDocument is getting validated

The issue is that both cases 2 and 3 are valid per the schema - your schema doesn't have any opinion on elements in namespaces other than its targetNamespace.

XmlReader can return a warning for this, but there's no overload for XDocument that will do it. The snippet in your linked question uses an XmlReader wrapper around XDocument, I can't see why you'd have any issue with doing it this way.

XDocument.Validate not catching all errors against XSD

It seems that XmlReader stops validation of element on first encountered error. Here is a link to description of old (obsolete) XmlValidatingReader ValidationEventHandler:

If an element reports a validation error, the rest of the content
model for that element is not validated, however, its children are
validated. The reader only reports the first error for a given
element.

And it seems it is the same with regular XmlReader (though its documentation does not mention it explicitly).

In first examples errors are either in innermost elements (such as invalid text value of element) or at the last child element, so they are all reported and nothing skipped. However in last example you introduce error at the beginning of root Abc001 element, so the rest of Abc001 content is skipped, together with all errors.

Partial XML file validation using XSD

You have a few issues here:

  1. Validating the entire document succeeds when it should fail.

    This happens because the root node is unknown to the schema, and encountering an unknown node is considered a validation warning not a validation error - even if that unknown node is the root element. To enable warnings while validating, you need to set XmlSchemaValidationFlags.ReportValidationWarnings. However, there's no way to pass this flag to XDocument.Validate(). The question XDocument.Validate is always successful shows one way to work around this.

    Having done this, you must also throw an exception in your validation handler when ValidationEventArgs.Severity == XmlSeverityType.Warning.

    (As for requiring a certain root element in your XSD, this is apparently not possible.)

  2. You need a convenient way to validate elements as well as documents, so you can validate your <TestConfiguration> piece.

  3. Your XSD and XML are inconsistent.

    You XSD specifies that your elements are in the XML namespace MyApp_ConfigurationFiles in the line targetNamespace="MyApp_ConfigurationFiles" elementFormDefault="qualified". In fact the XML elements shown in your question are not in any namespace.

    If the XSD is correct, your XML root node needs to look like:

    <Root xmlns="MyApp_ConfigurationFiles">

    If the XML is correct, your XSD needs to look like:

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

After you have resolved the XSD and XML inconsistency from #3, you can solve issues #1 and #2 by introducing the following extension methods that validate both documents and elements:

public static class XNodeExtensions
{
public static void Validate(this XContainer node, XmlReaderSettings settings)
{
if (node == null)
throw new ArgumentNullException();
using (var innerReader = node.CreateReader())
using (var reader = XmlReader.Create(innerReader, settings))
{
while (reader.Read())
;
}
}

public static void Validate(this XContainer node, XmlSchemaSet schemaSet, XmlSchemaValidationFlags validationFlags, ValidationEventHandler validationEventHandler)
{
var settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags |= validationFlags;
if (validationEventHandler != null)
settings.ValidationEventHandler += validationEventHandler;
settings.Schemas = schemaSet;
node.Validate(settings);
}
}

Then, to validate the entire document, do:

try
{
var xsdDocument = XDocument.Load(xsdFilePath);
var schemaSet = new XmlSchemaSet();
using (var xsdReader = xsdDocument.CreateReader())
schemaSet.Add(XmlSchema.Read(xsdReader, this.XmlSchemaEventHandler));
var xmlDocument = XDocument.Load(xmlFile);

xmlDocument.Validate(schemaSet, XmlSchemaValidationFlags.ReportValidationWarnings, XmlValidationEventHandler);
}
catch (Exception e)
{
Logger.Info("Error parsing XML file: " + xmlFile);
throw new Exception(e.Message);
}

And to validate a specific node, you can use the same extension methods:

XNamespace elementNamespace = "MyApp_ConfigurationFiles";
var elementName = elementNamespace + "TestConfiguration";

try
{
var xsdDocument = XDocument.Load(xsdFilePath);
var schemaSet = new XmlSchemaSet();
using (var xsdReader = xsdDocument.CreateReader())
schemaSet.Add(XmlSchema.Read(xsdReader, this.XmlSchemaEventHandler));
var xmlDocument = XDocument.Load(xmlFile);

var element = xmlDocument.Root.Element(elementName);
element.Validate(schemaSet, XmlSchemaValidationFlags.ReportValidationWarnings, this.XmlValidationEventHandler);
}
catch (Exception e)
{
Logger.Info(string.Format("Error validating element {0} of XML file: {1}", elementName, xmlFile));
throw new Exception(e.Message);
}

Now validating the entire document fails while validating the {MyApp_ConfigurationFiles}TestConfiguration node succeeds, using the following validation event handlers:

void XmlSchemaEventHandler(object sender, ValidationEventArgs e)
{
if (e.Severity == XmlSeverityType.Error)
throw new XmlException(e.Message);
else if (e.Severity == XmlSeverityType.Warning)
Logger.Info(e.Message);
}

void XmlValidationEventHandler(object sender, ValidationEventArgs e)
{
if (e.Severity == XmlSeverityType.Error)
throw new XmlException(e.Message);
else if (e.Severity == XmlSeverityType.Warning)
throw new XmlException(e.Message);
}

Validating XML documents with XSD correctly

There is no nodes in your XML that can be validated by the schema (namespaces are different). As result it does not report any errors. As far as I know behavior for nodes that are not matched to any schema is allow anything.

You also could set validation options in XmlReaderSettings to allow warnings:

ReportValidationWarnings - Indicates that events should be reported if a validation warning occurs. A warning is typically issued when there is no DTD or XML Schema to validate a particular element or attribute against. The ValidationEventHandler is used for notification.

Check out XmlSchemaSet.Add and HOW TO: Validate an XML Document by Using Multiple Schemas if you expect nodes from multiple namespaces to be present in the XML.

xsd validation limit root element

Result.

Validate() catches only errors, not warnings.

xmlReader has more options to check xml by xsd

If xml and xsd have different namespaces, validate() will be always true.
To fix it you should remove namespaces from both files or write the same namespace.

XDocument.Parse Success or Failure?

Is Try Catch the only way to do this?

There is no TryParse method for XDocument, so try-catch is probably the best bet. Also consider validating your XML against a schema since it will not only check if the XML is well-formed, but also checks for constraints.

You may see: Validation Against XML Schema (XSD) with the XmlValidatingReader

Validate xml against xsd without considering xml namesapce

The namespace is a part of the element name, so there's not much you can do other than ensure they are correct.

If all the element namespaces are supposed to be the same, you could set the namespace on all your elements before validating:

XNamespace ns = "urn:testnew/properties/v1.0";

foreach (var element in xmlDocument.Descendants())
{
element.Name = ns + element.Name.LocalName;
}

xmlDocument.Validate(...);

Unfortunately, if the namespace doesn't match then the XML is valid according to the schema (provided it is well formed) as the schema simply doesn't apply to the elements. The validation can raise a warning to say the elements aren't recognised, though it's not possible to pass this flag via the XDocument.Validate extension method (as far as I can tell!).

This question shows an alternate validation method using XmlReader and XmlReaderSettings that would allow you to capture warnings if the schema does not recognise elements.



Related Topics



Leave a reply



Submit