40

I have an XML document similar to the following:

<scan_details>
    <object name="C:\Users\MyUser\Documents\Target1.doc">
        ...
    </object>
    <object name="C:\Users\MyUser\Documents\Target2.doc">
        ...
    </object>
    ...
</scan_details>

I am hoping to use the System.Xml.Serialization attributes to simplify XML deserialization. The issue I have is I cannot work out how to specify that the root node contains an array.

I have tried creating the following classes:

[XmlRoot("scan_details")]
public class ScanDetails
{
    [XmlArray("object")]
    public ScanDetail[] Items { get; set; }
}

public class ScanDetail
{
    [XmlAttribute("name")]
    public string Filename { get; set; }
}

However when I deserialize the XML into the ScanDetails object the Items array remains null.

How do I deserialize an array in a root node?

Hand-E-Food
  • 12,368
  • 8
  • 45
  • 80

1 Answers1

73

You should use [XmlElement], and not [XmlArray] to decorate the Items property - it's already an array, and you only want to set the element name.

public class StackOverflow_12924221
{
    [XmlRoot("scan_details")]
    public class ScanDetails
    {
        [XmlElement("object")]
        public ScanDetail[] Items { get; set; }
    }

    public class ScanDetail
    {
        [XmlAttribute("name")]
        public string Filename { get; set; }
    }

    const string XML = @"<scan_details> 
                            <object name=""C:\Users\MyUser\Documents\Target1.doc""> 
                            </object> 
                            <object name=""C:\Users\MyUser\Documents\Target2.doc""> 
                            </object> 
                        </scan_details> ";

    public static void Test()
    {
        XmlSerializer xs = new XmlSerializer(typeof(ScanDetails));
        MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(XML));
        var obj = xs.Deserialize(ms) as ScanDetails;
        foreach (var sd in obj.Items)
        {
            Console.WriteLine(sd.Filename);
        }
    }
}
carlosfigueira
  • 85,035
  • 14
  • 131
  • 171
  • 1
    Ah... That's confusing terminoligy they use. I'd been focusing on `XmlArray` and `XmlArrayItem`. Thanks for that! – Hand-E-Food Oct 16 '12 at 22:24
  • 1
    If an array, but not just under the root level, then the array property still seems to need [XmlArray("arrayElementName")], and not [XmlElement("arrayElementItemName")], but if under the root level like your answer it needs [XmlElement("arrayElementItemName")] do you know why that is? It's like at the root level you are describing the inner repeating element types, and elsewhere the array type. – CRice Jul 02 '15 at 23:20
  • I just want to take a moment to thank you. I scoured through many answers on many questions and this is the only thing that works. It is so unintuitive that you don't need to define the array attribute on the root element, nor the array element. – Gaugeforever Mar 21 '17 at 02:32
  • If the element contains sub elements which are all of the same type, or all derived from the same type then you can use XmlElement. If the element contains several different collection with unrelated types, then you'll need to use XmlArray to have a sub element for each collection. This is a detail of XML, you can't have unrelated types in the same collection, the attributes just reflect that. – Tamir Daniely Mar 07 '19 at 14:10