如何将xml转换为对象列表

时间:2017-11-07 12:47:34

标签: c# xml xmlserializer xelement xattribute

这是我的目标是迭代所有节点而不仅仅是一个节点的代码,因此在我的情况下,它会立即获得第一个设备节点和所有子节点,因此我如何获得每个Device和PortA PortB节点。然后我就可以设置我的班级值了。

private void loadXmlFile(string path)
{
    try
    {
        XElement deviceElement = XElement.Load(path);
        Device device = new Device();
        var allElements = deviceElement.DescendantNodes();
        foreach (var elm in deviceElement.Elements())
        {
            if (elm.Name == "Device")
            {
                foreach (XAttribute att in elm.Attributes())
                {
                    if (att.Name == "Type")
                    {
                        device.TBType1 = att.Value.ToString();
                    }
                    if (att.Name == "Name")
                    {
                        device.Name = att.Value.ToString();
                    }
                    if (att.Name == "ParentConnectedToPort")
                    {
                        device.ParentConnectedTo = att.Value.ToString();
                    }
                    if (att.Name == "DeviceConnectedToPort")
                    {
                        device.DeviceConnectedTo = att.Value.ToString();
                    }

                    string connectedTo = (string)elm.Parent.Attribute("Connected_BY");
                    if (att.Name == "properties" && connectedTo == "Directly")
                    {
                        string str = att.Value;
                        string[] parts = str.Split(':', ',');
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

这是我的XML文件看起来需要获取每个设备元素及其自己的值并设置为我的类值。

<CMS>
  <Device Name="CM_HOST" Type="TR">
    <PortA Connected_BY="Directly">
      <Device TB="AR" ParentConnectedToPort="A" Name="Akitio" DeviceConnectedToPort="A" properties="{'Type': 'AR' ,'Name': 'Akitio','Cable': '20G Passive'}">
        <PortB Connected_BY="Directly">
          <Device TB="AR" ParentConnectedToPort="A" Name="doc1" DeviceConnectedToPort="B" properties="{'Type': 'AR' ,'Name': 'doc1','Cable': '20G Passive'}">
            <PortB Connected_BY="Directly">
              <Device TB="AR" ParentConnectedToPort="A" Name="doc2" DeviceConnectedToPort="B" properties="{'Type': 'AR' ,'Name': 'doc2','Cable': '20G Passive'}" />
            </PortB>
            <PortA Connected_BY="None" />
            <PortE Connected_BY="None" />
          </Device>
        </PortB>
        <PortA Connected_BY="None" />
        <PortE Connected_BY="None" />
      </Device>
    </PortA>
    <PortB Connected_BY="None" />
    <PortE Connected_BY="None" />
  </Device>
  <Sx properties="{'FTDI_port': '0' ,'SX_power_button_pin': '7','SX_SLP_S3_pin': '6','SX_SLP_S4_pin': '11','SX_SLP_S5_pin': '10','SX_TBT_wake_N_pin': '8','SX_PCIE_wake_pin': '9','G3_Power_Mode': 'PowerSplitter'}" />
</CMS>

3 个答案:

答案 0 :(得分:0)

使用XPath,您可以通过选择路径来选择节点列表。

答案 1 :(得分:0)

Xml序列化可能能够做你想要的。不完全确定你的最终结果是什么。您可以使用下面的类来简单地读取xml数据,然后从结果中创建所需的对象。

创建类。

public class CMS
{
    [XmlElement("Device")]
    List<Device> Devices {get;set;}

    //other properties here...
}

public class Device
{
    public Port PortA { get;set;}
    public Port PortB { get;set;}
    public Port PortC { get;set;}
    public Port PortD { get;set;}
    public Port PortE { get;set;}

    //other properties here...TB, ParentConnectedToPort etc
}

public class Port
{
    public Device Device { get; set; }


    //other properties here...Connected_BY etc
}

然后您可以使用此函数从字符串反序列化:

    public static T DeserializeXml<T>(string str)
    {
        var serializer = new XmlSerializer(typeof(T));
        object result;

        using (TextReader reader = new StringReader(str))
        {
            result = serializer.Deserialize(reader);
        }

        return (T) result;
    }

因此使用:

var s = "--your xml string--";
var obj = Deserialize<CMS>(s);
然后,

obj将成为xml数据中一个完全填充的对象。如果这是你想要的东西我可以填补上面的空白。

答案 2 :(得分:0)

我喜欢使用递归算法:

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



namespace ConsoleApplication13
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            XElement cms = doc.Descendants("CMS").FirstOrDefault();
            XElement device = cms.Element("Device");

            Device.RecursiveParseXml(device, Device.root);

        }

    }
    public class Device
    {

        public static Device root = new Device();

        public List<Port> ports { get; set; }

        public string name { get; set; }
        public string type { get; set; }
        public string tb { get; set; }
        public string deviceConnectedToPort { get; set; }
        public Dictionary<string, string> properties { get; set; }

        public static void RecursiveParseXml(XElement parent, Device device)
        {
            device.name = (string)parent.Attribute("Name");
            device.type = (string)parent.Attribute("Type");
            device.tb = (string)parent.Attribute("TB");
            device.deviceConnectedToPort = (string)parent.Attribute("DeviceConnectedToPort");
            string strProperties = (string)parent.Attribute("properties");
            if (strProperties != null)
            {
                string[] propertyArray = strProperties.Split(new char[] { ',', '{', '}' }, StringSplitOptions.RemoveEmptyEntries).ToArray();
                string pattern = @"'(?'name'[^']+)':\s+'(?'value'[^']+)";
                device.properties = new Dictionary<string, string>();
                foreach (string property in propertyArray)
                {
                    Match match = Regex.Match(property, pattern);

                    device.properties.Add(match.Groups["name"].Value, match.Groups["value"].Value);
                }

            }
            foreach (XElement element in parent.Elements())
            {
                Port newPort = new Port();
                if (device.ports == null)
                {
                    device.ports = new List<Port>();
                }
                device.ports.Add(newPort);

                newPort.connectBy = (string)element.Attribute("Connected_BY");

                XElement newDevice = element.Element("Device");
                if (newDevice != null)
                {
                    newPort.device = new Device();
                    RecursiveParseXml(element.Element("Device"), newPort.device);
                }
            }
        }
    }
    public class Port
    {
        public string name { get; set; }
        public string connectBy { get; set; }
        public Device device { get; set; }
    }

}