Fred
Fred

Reputation: 5808

Validating XML and Displaying what failed

I am trying to validate an XML file and display any errors to the user.

Simplified Example:

XML:

<MyApps>
  <MyApp>
    <Header>
      <Name>Name 1</Name>
      <Rate>4</Rate>
    </Header>
    <Players>
      <Player>
        <Name>Bert</Name>
        <Age>22</Age>
      </Player>
      <Player>
        <Name>Harry</Name>
        <Age>12</Age>
      </Player>
      <Player>
        <Name>George</Name>
        <Age>16</Age>
      </Player>    
    </Players>
  </MyApp>
  <MyApp>
    <Header>
      <Name>Name 2</Name>
      <Rate>3</Rate>
    </Header>
    <Players>
      <Player>
        <Name>Fred</Name>
        <Age>29</Age>
      </Player>
      <Player>
        <Name>Bill</Name>
        <Age>19</Age>
      </Player>
      <Player>
        <Name>Garry</Name>
        <Age>20</Age>
      </Player>    
    </Players>
  </MyApp>
</MyApps>

Validator:

public class XMLValidationMessage
{
    public int LineNumber;
    public int LinePosition;
    public string Message;
    public XmlSeverityType Severity;
}
public class XMLValidationResponse
{

    /// <summary>
    /// Result of the XML Validation.
    /// </summary>
    [Description("Result of the XML Validation")]
    public bool IsXMLValid { get; set; }

    /// <summary>
    /// XML Validation Errors.
    /// </summary>
    [Description("XML Validation Errors")]
    public List<XMLValidationMessage> ValidationErrors { get; set; }


    public XMLValidationResponse()
    {
        ValidationErrors = new List<XMLValidationMessage>();
    }
}


    private static XMLValidationResponse response = new XMLValidationResponse();

    public static XMLValidationResponse ValidateXML(string XMLFile, string XSDFile)
    {
        XmlSchemaSet schemaSet = new XmlSchemaSet();
        schemaSet.Add(null, XSDFile);
        response.IsXMLValid = true;
        Validate(XMLFile, schemaSet);
        return response;
    }
    private static void Validate(String filename, XmlSchemaSet schemaSet)
    {

        XmlSchema compiledSchema = null;

        foreach (XmlSchema schema in schemaSet.Schemas())
        {
            compiledSchema = schema;
        }

        XmlReaderSettings settings = new XmlReaderSettings();
        settings.Schemas.Add(compiledSchema);
        settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
        settings.ValidationType = ValidationType.Schema;

        //Create the schema validating reader.
        XmlReader vreader = XmlReader.Create(filename, settings);

        while (vreader.Read()) { }

        //Close the reader.
        vreader.Close();
    }

    private static void ValidationCallBack(object sender, ValidationEventArgs args)
    {
        response.IsXMLValid = false;
        if (args.Severity == XmlSeverityType.Warning)
        {
            XMLValidationMessage xmlm = new XMLValidationMessage();
            xmlm.Severity = XmlSeverityType.Warning;
            xmlm.LineNumber = 0;
            xmlm.LinePosition = 0;
            xmlm.Message = "Matching schema not found.  No validation occurred.";
            response.ValidationErrors.Add(xmlm);
        }
        else
        {
            XMLValidationMessage xmlm = new XMLValidationMessage();
            xmlm.Severity = XmlSeverityType.Error;
            xmlm.LineNumber = args.Exception.LineNumber;
            xmlm.LinePosition = args.Exception.LinePosition;
            xmlm.Message = args.Message;
            response.ValidationErrors.Add(xmlm);
        }

    }

If the XML fails validation I get a List of errors in the form of XMLValidationMessage. This gives me a line number, Line position and message. However, there seems to be no way to link the error to the XML element that caused the error. After validation I deserialise the XML into a data class object then use this to populate a tree view. Ultimately what I want to do is highlight the branches of the treeview that failed validation. I am thinking that maybe I am going about this the wrong way?

Update - Example Error

ValidationErrors    Count = 14  System.Collections.Generic.List<MyApp.Xml.XMLValidationMessage>
-   [0] {MyApp.Xml.XMLValidationMessage}    MyApp.Xml.XMLValidationMessage
    LineNumber  89  int
    LinePosition    127 int
    Message "The 'http://www.myweb.co.uk/srm/mscc:Remarks' element is invalid - The value 'Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit...' is invalid according to its datatype 'http://www.MyWeb.co.uk/srm/mscc:String50Type' - The actual length is greater than the MaxLength value."    string
    Severity    Error   System.Xml.Schema.XmlSeverityType

I get a collection of errors that are all valid errors. Not sure if the Schema would help that part is working fine. The trouble I am haiving is linking the error to the XML element causing the error.

Upvotes: 1

Views: 1354

Answers (1)

Rob Davis
Rob Davis

Reputation: 1319

That data can be found in the sender argument in your ValidationCallbackMethod. I added a couple of lines to the else statement of the example ValidationCallbackMethod you posted.

private static void ValidationCallBack(object sender, ValidationEventArgs args)
{
    response.IsXMLValid = false;
    if (args.Severity == XmlSeverityType.Warning)
    {
        XMLValidationMessage xmlm = new XMLValidationMessage();
        xmlm.Severity = XmlSeverityType.Warning;
        xmlm.LineNumber = 0;
        xmlm.LinePosition = 0;
        xmlm.Message = "Matching schema not found.  No validation occurred.";
        response.ValidationErrors.Add(xmlm);
    }
    else
    {
        // this will give you the name of the schema element that failed validation 
        var schemaInfo = ((XmlReader)sender).SchemaInfo;
        var elementThatFailedValidation = schemaInfo.SchemaElement.Name;

        XMLValidationMessage xmlm = new XMLValidationMessage();
        xmlm.Severity = XmlSeverityType.Error;
        xmlm.LineNumber = args.Exception.LineNumber;
        xmlm.LinePosition = args.Exception.LinePosition;
        xmlm.Message = args.Message;
        response.ValidationErrors.Add(xmlm);
    }

}

Upvotes: 1

Related Questions