views:

337

answers:

3

I need to read in XML data posted from external systems, which will be formatted roughly as follows:

<Applicant>
  <FirstName>John</FirstName>
  <LastName>Smith</LastName>
  <Address>12 Main St</Address>
</Applicant>

This is a direct mapping of my Linq to SQL Applicant class, excluding a few properties.

What's the best way to deserialize xml into a Linq to SQL object, so I can then insert directly into my database? I'd also like to validate the incoming XML and handle specific errors if possible.

Thanks in advance!

A: 

To validate, you need a XML schema for these XML files coming in - you can fairly easily create one using the xsd.exe tool in your Windows SDK directory which takes a XML file and turns it into a xsd (XML schema) file.

If you already have a class that basically matches this XML, yes, the easiest would probably be to just deserialize it into an Applicant class:

XmlSerializer ser = new XmlSerializer(typeof(Applicant));
StreamReader sr = new StreamReader(.....); // depends on where you get your XML from
Applicant result = (Applicant)ser.Deserialize(sr);

That should fill up your Applicant object with those properties coming from the XML - this will work as long as you don't leave any required properties empty (and don't have a means to provide a valid default value), and if you don't have any type mismatches in your mappings (e.g. trying to deserialize a string into an INT property or something like that).

marc_s
+3  A: 

If it is a direct map, you should just be able to use it directly, as long as the types as public and have public parameterless constructors, and the properties (including lists) are get/set.

If you need to tweak the names there is an XmlSerializer constructor that allows you to specify all the attributes. This is ideal for your scenario, but you must cache and re-use the serializer if you use this constructor overload, otherwise you will leak memory (the dynamic assemblies are not collected).

Here's a full example that removes one property (XmlIgnore), changes another to an attribute, and leaves a third as an element.

using System;
using System.IO;
using System.Xml.Serialization;
public class Foo
{
    public int A { get; set; }
    public string B { get; set; }
    public int C { get; set; }
}
static class Program
{
    static readonly XmlSerializer serializer;
    static Program()
    {
        XmlAttributeOverrides or = new XmlAttributeOverrides();
        or.Add(typeof(Foo), "A", new XmlAttributes { // change to an attrib
            XmlAttribute = new XmlAttributeAttribute("tweaked")
        });
        or.Add(typeof(Foo), "B", new XmlAttributes {
            XmlIgnore = true // turn this one off
        });
        // leave C as a default named element
        serializer = new XmlSerializer(typeof(Foo), or);
    }
    static void Main()
    {
        Foo foo = new Foo { A = 123, B = "def", C = 456 }, clone;
        string xml;
        using (StringWriter sw = new StringWriter())
        {
            serializer.Serialize(sw, foo);
            xml = sw.ToString();
        }
        using (StringReader sr = new StringReader(xml)) {
            clone = (Foo)serializer.Deserialize(sr);
        }
        Console.WriteLine(xml);
        Console.WriteLine();
        Console.WriteLine(clone.A);
        Console.WriteLine(clone.B);
        Console.WriteLine(clone.C);
    }
}

Note also that if you only need to change things at the type level (such as [XmlInclude]) then you can do this via the partial class that LINQ-to-SQL generates; for example:

namespace My.Dal.Namespace {
    // add a type attribute to SomeEntity
    [XmlInclude(typeof(SomeDerivedEntity))]
    partial class SomeEntity { } 
}
Marc Gravell
Unfortunately, he says it's a direct map, _excluding a few properties_.
John Saunders
@John In which case it *isn't* a direct map, and it can be done by using the overloaded constructor
Marc Gravell
@Marc: so that constructor allows you to force in an XmlIgnore? I did not know that. An example would be good.
John Saunders
@John - hit F5 ;-p
Marc Gravell
@Marc, you're _way_ too fast!
John Saunders
Great response Marc (as always) - Thanks!
Marcus
A: 

It's much more simpler.

First use a DataContractSerializer to Serialize your LinqToXml Entities. This returns a byte array. With Encoding.UTF8.GetString(the byte array from DataContractSerializer) you get a xml representation of your entities...

Hope it helps

lowtekk