views:

67

answers:

3

I am trying to load data from XML string into a structure of some sort so once loaded I can then say Data.PropertyName to read the values.

Is the below code the most optimal way of loading the data into the structure?

Obviously calling First() has a memory hit so if you have elements with sub elements will calling First() for each one become an issue?

Thanks

    string xml = @"<ROOT>
                   <ID>1</ID>
                   <NAME>RF1</NAME>
                   <STAT>10200</STAT>
                   <TEST>
                       <ID>1</ID>
                       <NAME>BIGUN</NAME>
                   </TEST>
                   </ROOT>
                   ";

     XElement Data = XElement.Parse(xml);


     var Element = (from p in Data.Descendants("ROOT") 
                   select new { 
                        ID = (int)p.Element("ID"), 
                        Test = new { 
                                    ID = p.Element("TEST").Descendants("ID").First(), 
                                    NAME = p.Element("TEST").Descendants("NAME").First() 
                                 }, 
                        Stat = p.Element("STAT") }).First();

//Read Element.ID, Element.Test.Name
+1  A: 

I'd go for deserialization and Xml attributes: much more readable.

Pawel Lesnikowski
Could you provide an example or link to an example?
Jon
Marc already did.
Pawel Lesnikowski
+3  A: 

You could use XmlSerializer to deserialize it?

using System;
using System.IO;
using System.Xml.Serialization;

[XmlRoot("ROOT")]
public class MyType
{
    [XmlElement("ID")]
    public string Id { get; set; }
    [XmlElement("NAME")]
    public string Name { get; set; }
    [XmlElement("STAT")]
    public string Stat { get; set; }
    [XmlElement("TEST")]
    public MyOtherType Nested { get; set; }
}
public class MyOtherType
{
    [XmlElement("ID")]
    public string Id { get; set; }
    [XmlElement("NAME")]
    public string Name { get; set; }
}
static class Program
{

    static void Main()
    {
        string xml = @"<ROOT>
                   <ID>1</ID>
                   <NAME>RF1</NAME>
                   <STAT>10200</STAT>
                   <TEST>
                       <ID>1</ID>
                       <NAME>BIGUN</NAME>
                   </TEST>
                   </ROOT>";
        MyType obj = (MyType) new XmlSerializer(typeof(MyType))
            .Deserialize(new StringReader(xml));
        Console.WriteLine(obj.Id);
        Console.WriteLine(obj.Name);
        Console.WriteLine(obj.Stat);
        Console.WriteLine(obj.Nested.Id);
        Console.WriteLine(obj.Nested.Name);
    }
}
Marc Gravell
Wow, thanks. Have never seen that approach before. Would you say this is more efficient than LINQ or very similar? What if you have a property in the class that relates to a XMLElement that doesn't appear in the XML, does it throw an exception or just sets the value of the property to null?
Jon
@Jon: I expect it to be slightly less efficient than LINQ, as it has to use reflection to find out what to read from the XML. You would have to profile the code to find out for certain. You can use the IsNullable property in the XmlElement attribute to specify if the element is required in the XML.
Guffa
A: 

No, it's not the most optimal way, but it's likely to be good enough.

The most optimal for performance would be to write your own XML parser that is specialised for just this, but that would of course be a lot more code.

I don't know why you are concerned with the First method. It will just let the first item through and then stop reading, so it won't cause any problems. The XML parser still has to parse all the children, of course.

Guffa