elunap
elunap

Reputation: 841

C# Deserializing a XML to an object List

I have this XML structure:

<?xml version="1.0" encoding="UTF-8" ?>
<response uri="/api/" action="EXPORT">
<result>
    <rows>
        <row>
            <column name="Name1">Value1</column>
            <column name="Name2">Value2</column>
        </row>
        <row>
            <column name="Name1">Value1</column>
            <column name="Name2">Value2</column>
        </row>
    </rows>
</result>
</response>

I'm trying to deserialize the XML into a list object like so:

 List<ModelXML> model;

        using (TextReader reader = new StringReader(xml_str))
        {
            System.Xml.Serialization.XmlSerializer deserializer = new System.Xml.Serialization.XmlSerializer(typeof(List<ModelXML>),
                new XmlRootAttribute("rows"));
            model= (List<ModelXML>)deserializer.Deserialize(reader);
        }

My parameters in the ModelXML Class:

    [XmlElement("Name1")]
    public string Name1{ set; get; }
    [XmlElement("Name2")]
    public string Name2{ set; get; }

And finally I'm getting this error:

The '=' character, hexadecimal value 0x3D, cannot be included in a name. Line 1, position 13.

What I'm doing wrong? thanks.

Upvotes: 0

Views: 533

Answers (2)

NtFreX
NtFreX

Reputation: 11367

When I run your code I get the following exception.

System.InvalidOperationException: 'There is an error in XML document (2, 2).'

InnerException

InvalidOperationException: < response xmlns='' > was not expected.

This is because you must define the outer most element as the root element and not one deeper in the structure like your tried to do. One way to solve this is by defining all nessesary model classes like @BRAHIM Kamel did.


Ïf you don't want to have so many model classes and you don't care to much about performance you could also do this.

[XmlRoot("row")]
public class ModelXML
{
    public class Column
    {
        [XmlAttribute("name")]
        public string Name { set; get; }
        [XmlText]
        public string Value { set; get; }
    }

    [XmlElement("column")]
    public List<Column> Columns { get; set; }
}

IEnumerable<T> Deserialize<T>(IEnumerable<XElement> elements)
{
    foreach (var element in elements)
    {
        using (var reader = XDocument.Parse(element.ToString()).CreateReader())
        {
            XmlSerializer deserializer = new XmlSerializer(typeof(T));
            yield return (T)deserializer.Deserialize(reader);
        }
    }
}

var document = XDocument.Parse(xml_str);
var collection = Deserialize<ModelXML>(
    document.XPathSelectElements("response/result/rows/row"));

Upvotes: 0

BRAHIM Kamel
BRAHIM Kamel

Reputation: 13765

Here how you can solve your issue

First you have to change your model

[XmlRoot(ElementName = "column")]
    public class Column
    {
        [XmlAttribute(AttributeName = "name")]
        public string Name { get; set; }
        [XmlText]
        public string Text { get; set; }
    }

    [XmlRoot(ElementName = "row")]
    public class Row
    {
        [XmlElement(ElementName = "column")]
        public List<Column> Column { get; set; }
    }

    [XmlRoot(ElementName = "rows")]
    public class Rows
    {
        [XmlElement(ElementName = "row")]
        public List<Row> Row { get; set; }
    }

    [XmlRoot(ElementName = "result")]
    public class Result
    {
        [XmlElement(ElementName = "rows")]
        public Rows Rows { get; set; }
    }

    [XmlRoot(ElementName = "response")]
    public class Response
    {
        [XmlElement(ElementName = "result")]
        public Result Result { get; set; }
        [XmlAttribute(AttributeName = "uri")]
        public string Uri { get; set; }
        [XmlAttribute(AttributeName = "action")]
        public string Action { get; set; }
    }

Then use the deserialization code like the following

//here I'm trying to load the file from the disk but you can do the same by passing a string 

  Response  model;

            var xml = File.ReadAllText("file.xml");  
            using (TextReader reader = new StringReader(xml))
            {
                System.Xml.Serialization.XmlSerializer deserializer = new System.Xml.Serialization.XmlSerializer(typeof(Response));
                model = (Response)deserializer.Deserialize(reader);
            }   

More you can access your rows like this

var rows = model.Result.Rows; 

//hope this can help

Upvotes: 1

Related Questions