How can I deserialize a XML with this kind of stru

2019-08-24 13:09发布

I have a web service that when called gives me an XML result in the following structure:

<returns>
    <return>
        <name>firstName</name>
        <value>John</value>
    </return>
    <return>
        <name>lastName</name>
        <value>Doe</value>
    </return>
    <return>
        <name>dateOfBirth</name>
        <value>01-01-1900 00:00</value>
    </return>
    <return>
        <name>address</name>
        <value>100, Example Street</value>
    </return>
</returns>

If I go to Visual Studio > Edit > Paste Special > Paste XML As Classes I get the following code generated to me:

// NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class returns
{

    private returnsReturn[] returnField;

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

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

    private string nameField;

    private string valueField;

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

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

However what I would like to do is have a model class in the following structure, and then have the XML deserialized into it:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public string Address { get; set; }
}

How can I achieve this while having the provided XML structure? I have worked with JSON deserialization in the past, and if the return of the web service was something in the lines of this I would have no problem:

[
    {
        "firstName": "John",
        "lastName": "Doe",
        "dateOfBirth": "01-01-1900 00:00",
        "address": "100, Example Street"
    }
]

Or even if it was a XML with the following structure:

<customers>
    <customer>
        <firstName>John</firstName>
        <lastName>Doe</lastName>
        <dateOfBirth>01-01-1900 00:00</dateOfBirth>
        <address>100, Example Street</address>
    </customer>
</customers>

But I don't know how to deal or deserialize a XML composed of "name" and "value" fields. How can I work with (deserialize into it's proper model) this kind of XML using C# and .NET Core?

3条回答
聊天终结者
2楼-- · 2019-08-24 13:51

Try this one, It's a console app and it's working well with a Deserialize method to read xml from a file path and map it into a Person POCO class for you

namespace XMLDemo
{
    [System.Xml.Serialization.XmlRoot(ElementName = "return")]
    public struct Return
    {
        [System.Xml.Serialization.XmlElement(ElementName = "name")]
        public string Name { get; set; }
        [System.Xml.Serialization.XmlElement(ElementName = "value")]
        public string Value { get; set; }
    }

    [System.Xml.Serialization.XmlRoot(ElementName = "returns")]
    public struct Returns
    {
        [System.Xml.Serialization.XmlElement(ElementName = "return")]
        public System.Collections.Generic.List<Return> Return { get; set; }
    }

    public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public System.DateTime DateOfBirth { get; set; }
        public string Address { get; set; }


        public Person(Returns data)
        {
            this.FirstName = data.Return[0].Value;
            this.LastName = data.Return[1].Value;
            this.DateOfBirth = System.DateTime.Parse(data.Return[2].Value);
            this.Address = data.Return[3].Value;
        }
    }

    class Program
    {
        private const string _FILEPATH = @"D:\data.txt";
        static void Main(string[] args)
        {
            string xml = System.IO.File.ReadAllText(_FILEPATH);

            var returns = (Returns)Deserialize(xml, typeof(Returns));

            Person person = new Person(returns);

            System.Console.WriteLine(person.FirstName);
            System.Console.WriteLine(person.LastName);
            System.Console.WriteLine(person.DateOfBirth);
            System.Console.WriteLine(person.Address);
        }

        static object Deserialize(string serializedObj, System.Type type)
        {
            var serializer = new System.Xml.Serialization.XmlSerializer(type);

            using (var stringReader = new System.IO.StringReader(serializedObj))
            using (var xmlTextReader = new System.Xml.XmlTextReader(stringReader))
            {
                return serializer.Deserialize(xmlTextReader);
            }
        }
    }
}
查看更多
甜甜的少女心
3楼-- · 2019-08-24 13:56

Hi you can deserialize your XML by a using function something like below:

returns Deserialize(string xmlString)
{
     returns obj = null;
     using (TextReader textReader = new StringReader(xmlString))
            {
                using (XmlTextReader reader = new XmlTextReader(xmlString))
                {
                    reader.Namespaces = false;
                    XmlSerializer serializer = new XmlSerializer(typeof(returns));
                    obj = (returns)serializer.Deserialize(reader);

                }
            }
        return obj;
}

Call this function in your Person Class Constructor

public Person(string xmlString)
{
      var obj = Deserialize(xmlString);

       switch (name)
            {
                case "firstName" :
                    FirstName = value;
                    break;

                case "lastName":
                    LastName = value;
                    break;

                case "dateOfBirth":
                    DateOfBirth = DateTime.Parse(value);
                    break;

                case "address":
                    Address = value;
                    break;
            }
}

However a good approach is to design your xml response to return something like below:

<returns>
    <return>
        <firstName>John</firstName>
        <lastName>Doe</lastName>
        <dateOfBirth>01-01-1900 00:00</dateOfBirth>
        <address>100, Example Street</address>
    </return> 
</returns>

And then make your Person class Serializable that way you don't have to use the for loop and switch case to populate the values

查看更多
太酷不给撩
4楼-- · 2019-08-24 14:00

Try code below. I reading xml from file put you can use any string input. :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            string xml = File.ReadAllText(FILENAME);

            Person person = new Person(xml);
        }
    }
    public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime DateOfBirth { get; set; }
        public string Address { get; set; }


        public Person(string xml)
        {
            XDocument doc = XDocument.Parse(xml);

            foreach(XElement xReturn in doc.Descendants("return"))
            {
                string name = (string)xReturn.Element("name");
                string value = (string)xReturn.Element("value");

                switch (name)
                {
                    case "firstName" :
                        FirstName = value;
                        break;

                    case "lastName":
                        LastName = value;
                        break;

                    case "dateOfBirth":
                        DateOfBirth = DateTime.Parse(value);
                        break;

                    case "address":
                        Address = value;
                        break;
                }

            }

        }


    }
}
查看更多
登录 后发表回答