views:

431

answers:

2

Hi,

I'm using XmlSerializer to deserialize Xml achives. But I found the class xsd.exe generated only offers capability to read the xml, but no validation. For example, if one node is missing in a document, the attribute field of the generated class will be null, rather than throws a validation exception as I expected. How can I achieve that? Thanks!

+1  A: 

The following code will manually load and validate your XML against a schema file programmatically, allowing you to deal with any resulting errors and/or warnings.

//Read in the schema document
using (XmlReader schemaReader = XmlReader.Create("schema.xsd"))
{
    XmlSchemaSet schemaSet = new XmlSchemaSet();

    //add the schema to the schema set
    schemaSet.Add(XmlSchema.Read(schemaReader, 
 new ValidationEventHandler(
  delegate(Object sender, ValidationEventArgs e)
  {
  }    
 )));

    //Load and validate against the programmatic schema set
    XmlDocument xmlDocument = new XmlDocument();
    xmlDocument.Schemas = schemaSet;
    xmlDocument.Load("something.xml");

    xmlDocument.Validate(new ValidationEventHandler(
        delegate(Object sender, ValidationEventArgs e)
        {
            //Report or respond to the error/warning
        }
    )); 
 }

Now obviously you desire to have the classes generated by xsd.exe to do this automatically and while loading (the above approach would require a second handling of the XML file), but a pre-load validate would allow you to programmatically detect a malformed input file.

ee
-1 for missing `using` blocks, and for not directly addressing the question - he asked about deserialization, not about loading an `XmlDocument`.
John Saunders
@John Saunders - I am doubting that the class generation code is likely to change its operation any time soon, and the msdn site shows no relevant options for xsd.exe, so I think it is reasonable to suggest a workaround...
ee
@ee: I'm missing your point, completely. What does `XmlDocument` have to do with xsd.exe?
John Saunders
In the question text, the OP expresses that he wants an exception to be thrown for an invalid input xml. This approach does accomplish that. I am not claiming that this is the only way it can be done, or even that it is the best way. But I was responding with an approach (off the top of my head) that I had used in the past to generally validate XML documents.
ee
+3  A: 

The following code should validate against a schema while deserializing. Similar code can be used to validate against a schema while serializing.

private static Response DeserializeAndValidate(string tempFileName)
{
    XmlSchemaSet schemas = new XmlSchemaSet();
    schemas.Add(LoadSchema());

    Exception firstException = null;

    var settings = new XmlReaderSettings
                   {
                       Schemas = schemas,
                       ValidationType = ValidationType.Schema,
                       ValidationFlags =
                           XmlSchemaValidationFlags.ProcessIdentityConstraints |
                           XmlSchemaValidationFlags.ReportValidationWarnings
                   };
    settings.ValidationEventHandler +=
        delegate(object sender, ValidationEventArgs args)
        {
            if (args.Severity == XmlSeverityType.Warning)
            {
                Console.WriteLine(args.Message);
            }
            else
            {
                if (firstException == null)
                {
                    firstException = args.Exception;
                }

                Console.WriteLine(args.Exception.ToString());
            }
        };

    Response result;
    using (var input = new StreamReader(tempFileName))
    {
        using (XmlReader reader = XmlReader.Create(input, settings))
        {
            XmlSerializer ser = new XmlSerializer(typeof (Response));
            result = (Response) ser.Deserialize(reader);
        }
    }

    if (firstException != null)
    {
        throw firstException;
    }

    return result;
}
John Saunders
Thanks for sharing this solution. As this puts the validation in-line with the deserialize by validating via the XmlReader, it is a better approach.
ee