Click here to Skip to main content
14,828,874 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I got deserializing working with single element. But when I have array of xml elements, my code is not working.

Below is my code

What I have tried:

XML
<data>
    <cars>
        <body>
            <color>blue<color>
            <type>sedan</type>
        </body>
        <details>
            <year>2016</year>
            <make>Infiniti</make>
        </details>
    </cars>
    <cars>
        <body>
            <color>white<color>
            <type>SUV</type>
        </body>
        <details>
            <year>2016</year>
            <make>Lexus</make>
        </details>
    </cars>
</data>

Dto
C#
[XmlRoot("cars")]
public class CarDetails
{
	[XmlElement("body")]
	public Body BodyList { get; set; }

	[XmlElement("details")]
	public DetailsList details { get; set; }
}

public class Body
{
	public string Color { get; set; }
	public string Type { get; set; }
}

public class DetailsList
{
	public int Year { get; set; }
	public string Make { get; set; }
}

Below is the code for deserializing:
C#
CarDetails[] details;
XmlSerializer serializer = new XmlSerializer(typeof(CarDetails[]));
using (TextReader reader = new StringReader(output))
{
    details = (CarDetails[])serializer.Deserialize(reader);
}
Posted
Updated 18-Sep-17 16:05pm
v3

First, you have a problem with an invalid ending tag - here:
XML
<color>blue<color>

should be:
XML
<color>blue</color>

same with:
XML
<color>white<color>

should be:
XML
<color>white</color>

Next, You need to generate classes for your XML. Here are two options:

Option 1. (Preferred)

Here is a useful tool to generate classes from XML: [^]

Generates this:
C#
/* 
    Licensed under the Apache License, Version 2.0
    
    http://www.apache.org/licenses/LICENSE-2.0
    */
using System;
using System.Xml.Serialization;
using System.Collections.Generic;
namespace Xml2CSharp
{
    [XmlRoot(ElementName="body")]
    public class Body {
        [XmlElement(ElementName="color")]
        public string Color { get; set; }
        [XmlElement(ElementName="type")]
        public string Type { get; set; }
    }

    [XmlRoot(ElementName="details")]
    public class Details {
        [XmlElement(ElementName="year")]
        public string Year { get; set; }
        [XmlElement(ElementName="make")]
        public string Make { get; set; }
    }

    [XmlRoot(ElementName="cars")]
    public class Cars {
        [XmlElement(ElementName="body")]
        public Body Body { get; set; }
        [XmlElement(ElementName="details")]
        public Details Details { get; set; }
    }

    [XmlRoot(ElementName="data")]
    public class Data {
        [XmlElement(ElementName="cars")]
        public List<Cars> Cars { get; set; }
    }

}

Option 2.

Also, Visual Studio (tested on VS2017) can also generate classes from XML:
1. Copy XML data to the clipboard
2. In VS, Edit > Paste Special > "Paste Xml as classes"

Generates this:
C#
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class data
{

    private dataCars[] carsField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("cars")]
    public dataCars[] cars
    {
        get
        {
            return this.carsField;
        }
        set
        {
            this.carsField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class dataCars
{

    private dataCarsBody bodyField;

    private dataCarsDetails detailsField;

    /// <remarks/>
    public dataCarsBody body
    {
        get
        {
            return this.bodyField;
        }
        set
        {
            this.bodyField = value;
        }
    }

    /// <remarks/>
    public dataCarsDetails details
    {
        get
        {
            return this.detailsField;
        }
        set
        {
            this.detailsField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class dataCarsBody
{

    private string colorField;

    private string typeField;

    /// <remarks/>
    public string color
    {
        get
        {
            return this.colorField;
        }
        set
        {
            this.colorField = value;
        }
    }

    /// <remarks/>
    public string type
    {
        get
        {
            return this.typeField;
        }
        set
        {
            this.typeField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class dataCarsDetails
{

    private ushort yearField;

    private string makeField;

    /// <remarks/>
    public ushort year
    {
        get
        {
            return this.yearField;
        }
        set
        {
            this.yearField = value;
        }
    }

    /// <remarks/>
    public string make
    {
        get
        {
            return this.makeField;
        }
        set
        {
            this.makeField = value;
        }
    }
}

So for your question, Option 1. uses for the collection of cars:
C#
[XmlElement(ElementName="cars")]
public List<Cars> Cars { get; set; }

and Option 2. uses:
C#
private dataCars[] carsField;

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("cars")]
public dataCars[] cars
{
    get
    {
        return this.carsField;
    }
    set
    {
        this.carsField = value;
    }
}

Which could be simplified as:
C#
private dataCars[] carsField;

/// <remarks/>
[System.Xml.Serialization.XmlElement("cars")]
public dataCars[] cars
{
    get => carsField;
    set => carsField = value;
}
   
v3
I think you can do it like this, but you might have to change your class for this to work, I just used a "normal" class with public properties:
string xml = File.ReadAllText(@"test.xml");
List<CarDetails> res = new List<CarDetails>();
var serializer = new XmlSerializer(res.GetType());

using (TextReader reader = new StringReader(xml))
{
	res = (List<CarDetails>)serializer.Deserialize(reader);
}
   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900