views:

335

answers:

5

I want users to be able to export data as an XML file. Of course I want them to be able to later on import that same XML file however they always could change it or it could be a different XML file.

So I want to validate the XML file to check if it is in the format that I expect. So I guess I would need something like a schema to check just that it has to be through code.

So if I expect

<Root>
 <Something>
    <SomethingElse> </SomethingElse>
 </Something>
</Root>

I don't want some other format to be in the file other then the one I expect.

Also how would I validate fields? Like say I require that there must be some text in between tags. If it is blank the file is not valid.

So how could I do this?

Edit

I decided to use XML serialization so I know it will through an exception if it is the wrong format and ignore stuff that does not work. However I am not sure should I just go through it and C# to validate each of the records or should I try to make an xml schema to do it.

If I would want to do it through an xml schema with xml serialization how would that work? Like Do I first do something like I seen in the responses then de serialize it? Or how would I do it?

+6  A: 

There are a few ways to validate XML files. Check out How To Validate an XML Document by Using DTD, XDR, or XSD in Visual C# .NET

Also see Validating an XML against Referenced XSD in C# example

Another good example is Validate XML against XSD using code at runtime in C#

Here is the code from the last post:

public void ValidateXmlDocument(
    XmlReader documentToValidate, string schemaPath)
{
    XmlSchema schema;
    using (var schemaReader = XmlReader.Create(schemaPath))
    {
        schema = XmlSchema.Read(schemaReader, ValidationEventHandler);
    }

    var schemas = new XmlSchemaSet();
    schemas.Add(schema);

    var settings = new XmlReaderSettings();
    settings.ValidationType = ValidationType.Schema;
    settings.Schemas = schemas;
    settings.ValidationFlags =
        XmlSchemaValidationFlags.ProcessIdentityConstraints |
        XmlSchemaValidationFlags.ReportValidationWarnings;
    settings.ValidationEventHandler += ValidationEventHandler;

    using (var validationReader = XmlReader.Create(documentToValidate, 
           settings))
    {
        while (validationReader.Read()) { }
    }
}

private static void ValidationEventHandler(
    object sender, ValidationEventArgs args)
{
    if (args.Severity == XmlSeverityType.Error)
    {
        throw args.Exception;
    }
    Debug.WriteLine(args.Message);
}
SwDevMan81
+7  A: 

Here's a code snippet that you can use to do so:

using (FileStream stream = File.OpenRead(xsdFilepath))
{
    XmlReaderSettings settings = new XmlReaderSettings();

    XmlSchema schema = XmlSchema.Read(stream, OnXsdSyntaxError);
    settings.ValidationType = ValidationType.Schema;
    settings.Schemas.Add(schema);
    settings.ValidationEventHandler += OnXmlSyntaxError;

    using (XmlReader validator = XmlReader.Create(xmlPath, settings))
    {
        // Validate the entire xml file
        while (validator.Read()) ;
    }
}

The OnXmlSyntaxError function will be called when a syntax error occur.

Pierre-Luc Champigny
A: 

You can use LINQ to XML: http://msdn.microsoft.com/en-us/library/bb387037.aspx. This page also shows how to do that along with source to dump any invalid nodes: http://blogs.msdn.com/xmlteam/archive/2007/03/03/the-new-linq-to-xml-bridge-classes-to-system-xml.aspx

ebpower
A: 

You can use xml serialization in your classes:

[XmlType("Root", Namespace = "http://example.com/Root")]
[XmlRoot(Namespace = "http://example.com/Root.xsd", ElementName = "Root", IsNullable = false)]
public class Root {
  [XmlElement("Something")] 
  public Something Something { get; set; }
}

public class Something {
  [XmlElement("SomethingElse")]
  public SomethingElse SomethingElse { get; set; }
}

public class SomethingElse {
  [XmlText]
  public string Text { get; set; }
}

Serialize it like this:

var serializer = new XmlSerializer(typeof(Root));
serializer.Serialize(outputStrem, myRoot);

You can then test before deserializing, e.g.:

var serializer = new XmlSerializer(typeof(Root));
string xml = @"
  <Root xmlns='http://example.com/Root'&gt;
    <Something>
      <SomethingElse>Yep!</SomethingElse>
    </Something>
  </Root>"; // remember to use the XML namespace!
Debug.Assert(serializer.CanDeserialize(new XmlTextReader(new StringReader(xml))));

And then to deserialize simply:

Root newRoot = (Root)serializer.Deserialize(inputStream);

Your XSD is implicit. It matches your classes. To use richer XSDs, you can venture into Schema Providers.

Jordão
So your using that "xml" string as a a schema provider to check it? But if I wanted to I could make a XSD and do like required fields?
chobo2
No, the xml string is not the schema, it is the document that you want to validate. The schema is implicit on the class definitions, and that's what the `XmlSerializer.CanSerialize` uses to validate. You can get the implicit schema from the classes by using the xsd.exe utility.
Jordão
The xml attributes that control serialization do not cover all the XSD syntax. Unfortunately, I couldn't find an option for an xml attribute to be marked as required with the `XmlAttributeAttribute` class. So having an external XSD and validating an XML against it first would be necessary, if you don't use Schema Providers.
Jordão
So this is the path to the .xsd file? [XmlRoot(Namespace = "http://example.com/Root.xsd", ElementName = "Root", IsNullable = false)]?Like I always figured I needed a external XSD but I am still not sure how to tie it with XML serialization?
chobo2
There is no XSD file, the attributes in your classes implicitly define it. You can still extract it through the xsd.exe utility. The example.com/Root.xsd is the XML namespace, it can be anything, like a UUID, I've just chosen it poorly with an xsd extension, I'm going to change it. It could point to the real XSD url, but this fact would be opaque to the code; it would only help the external producers of the xml to know the schema beforehand.
Jordão