I'm trying to validate an Xml fragment using an Xml Schema with the XDocument.Validate extension method. Whenever an invalid Xml fragment is used the ValidationEventHandler fires properly, however both the LineNumber and LinePosition properties of the XmlSchemaValidationException are 0.

private bool Validate(XDocument doc)
{
    bool isValid = true;
    List<string> validationErrors = new List<string>();

    XmlSchemaSet schemas = new XmlSchemaSet();
    schemas.Add(null, "MyCustomSchema.xsd");

    doc.Validate(schemas, (sender, args) =>
    {
        validationErrors.Add(String.Format("{0}: {1} [Ln {2} Col {3}]", 
            args.Severity, 
            args.Exception.Message, 
            args.Exception.LineNumber, 
            args.Exception.LinePosition));

        isValid = false;
    }, false);

    return isValid;
}

My goal in the above example is to use validationErrors for informing a user as to why the validation failed. When this method is used, however, the LineNumber and LinePosition are both 0.

The snippet seems simple enough and appears to work as expected in terms of validating against both valid and invalid Xml fragments.

Thanks in advance!

3

There are 3 answers

2
Pawel On BEST ANSWER

You are not validating the textual representation of the Xml anymore but the object model. As a result there is no lines and positions because there is no file but XElement, XAttribute etc. objects in memory. Another helpful hint would be to ask yourself - what line and position should be returned if you modified (e.g. an elelment was added) the XDocument after it was loaded but before running validation? If you are not creating or modifying the Xml the fastest way would be to use XmlReader to validate your Xml document. As a bonus - if the input is a file or a stream - you should get line and position information in case of validation errors.

0
Miha Markic On

It's an old question, but here is a way to preserve positions when creating an XDocument instance - make sure you use LoadOptions.SetLineInfo

XDocument.Parse(xml, LoadOptions.SetLineInfo);

Then you can extract position within Validate method.

0
jbobbins On

In your ValidationEventHandler, sender implements the IXmlLineInfo interface, which contains members System.Xml.IXmlLineInfo.LineNumber and System.Xml.IXmlLineInfo.LinePosition

So you could do this:

doc.Validate(schemas, (sender, args) =>
{
    var lineInfo = sender as IXmlLineInfo;
    validationErrors.Add(String.Format("{0}: {1} [Ln {2} Col {3}]",
        args.Severity,
        args.Exception.Message,
        lineInfo?.LineNumber,
        lineInfo?.LinePosition));

    isValid = false;
}, false);