简体   繁体   中英

How to deserialize XML with repeating tag name with unique identifier as attribute?

I am trying to deserialize this xml where all the node has the same name with a unique identifier as an attribute.

<configuration>
    <setting name="host">
        <value>127.0.0.1</value>
    </setting>
    <setting name="port">
        <value>80</value>
    </setting>
</configuration>

The result I am trying to achieve is:

public class Configuration
{
    string host { get; set; }
    int port { get; set; }
}

I read the previous question and I am still stumbling with the fact they have the same tag name.

Thank you!

You can call this "old school" but it works.

  1. Copy the XML (or fragment, etc) and leverage Visual Studio (2015(?) and up - shot below is 2017 ) feature "Paste XML/JSON As Classes"

    Visual Studio 2017

    This helps tremendously with valid XML - particularly with the "proper" attributes that decorate the generated classes. Additionally, it's just a class, so you can customize it as you deem fit (while retaining the attributes).

    For more complex XML - such as namespaces/prefixes, you'll really appreciate this. If you don't have this tool, you can use XSD.exe (even more old school) - does the same thing for XML documents.

  2. Auto-generated Classes from above step:

    ...stumbling with the fact they have the same tag name...

    Don't be. XML elements can repeat - often do (eg sitemap.xml of every web site out there). The generated class will help you grok it. It's a standard collection/array/list.

     [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] public partial class configuration { private configurationSetting[] settingField; /// <remarks/> [System.Xml.Serialization.XmlElementAttribute("setting")] public configurationSetting[] setting { get { return this.settingField; } set { this.settingField = value; } } } [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] public partial class configurationSetting { private string valueField; private string nameField; /// <remarks/> public string value { get { return this.valueField; } set { this.valueField = value; } } /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute()] public string name { get { return this.nameField; } set { this.nameField = value; } } } 

Given the above, you can do this:

string rawXml = "<configuration><setting name=\"host\"><value>127.0.0.1</value></setting><setting name=\"port\"><value>80</value></setting></configuration>";

var ser = new XmlSerializer(typeof(configuration));
configuration config;
using (TextReader rdr = new StringReader(rawXml))
{
    config = (configuration)ser.Deserialize(rdr);
}


foreach (configurationSetting setting in config.setting)
{
    Console.WriteLine($"{setting.name} = {setting.value}");
}

Output:

host = 127.0.0.1
port = 80

Hth..

Load your xml as a doc

XmlDocument doc = new XmlDocument();
doc.LoadXml(your_xml_data);

Then iterate through the child nodes

Configuration configuration = new Configuration();
XmlNode root = doc.FirstChild;

//fill the configuration from the child nodes.
if (root.HasChildNodes)
{
 if(root.ChildNodes[0].Name == "host")
 {
    configuration.host = root.ChildNodes[0].InnerText;
 }
 if(root.ChildNodes[1].Name == "port")
 {   
    configuration.port = root.ChildNodes[1].InnerText;
 }
}

Try this:

        XmlDocument doc = new XmlDocument();
        doc.LoadXml("yourxmlhere");

        Configuration configuration = new Configuration();
        XmlNode root = doc.FirstChild;
        if (root.HasChildNodes)
        {
            foreach (XmlNode item in root.ChildNodes)
            {
                configuration = SetValueByPropertyName(configuration, item.Attributes["name"].Value, item.FirstChild.InnerText);
            }
        }

The helper method to set values:

public static TInput SetValueByPropertyName<TInput>(TInput obj, string name, string value)
        {
            PropertyInfo prop = obj.GetType().GetProperty(name);
            if (null != prop && prop.CanWrite)
            {
                if (prop.PropertyType != typeof(String))
                {
                    prop.SetValue(obj, Convert.ChangeType(value, prop.PropertyType), null);
                }
                else
                {
                    prop.SetValue(obj, value, null);
                }
            }
            return obj;
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM