Search code examples
c#xmlserialization

How do I fix an empty List when deserializing XML in C#?


Trying to deserialize Networks object which contains a List called Controller which has 3 entries. Within Controller is another List called network. The Controller List is always empty. I have reviewed several posts in StackOverflow but nothing has helped. Any help will be greatly appreciated.

I have defined the following Class

using System;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace TestXML
{

    [Serializable()]
    [XmlRoot("Networks")]
    public class Networks
    {
        [XmlArray(ElementName = "Controller")]
        [XmlArrayItem("NetworkController")]
        public List<NetworkController> Controller { get; set; }

        [XmlAttribute("computer")]
        public string computer { get; set; }

        [XmlAttribute("GlobalFPPProxy")]
        public string GlobalFPPProxy { get; set; }

        [XmlAttribute("GlobalForceLocalIP")]
        public string GlobalForceLocalIP { get; set; }

    }

    [XmlType("NetworkController")]
    public class NetworkController
    {
        //[XmlElement(ElementName = "Id")]
        [XmlAttribute (AttributeName ="Id")]
        public string Id { get; set; }

        //[XmlElement(ElementName = "Name")]
        [XmlAttribute(AttributeName = "Name")]
        public string Name { get; set; }

        [XmlArray(ElementName = "network")]
        [XmlArrayItem("NetworkControllerNetwork")]
        public List<NetworkControllerNetwork> network { get; set; }

    }


    [XmlType("NetworkControllerNetwork")]
    public class NetworkControllerNetwork
    {
        [XmlAttribute(AttributeName = "ComPort")]
        public string ComPort { get; set; }

        [XmlAttribute("BaudRate")]
        public int BaudRate { get; set; }

        [XmlAttribute("NetworkType")]
        public string NetworkType { get; set; }

        [XmlAttribute("MaxChannels")]
        public int MaxChannels { get; set; }

    }

}

And I use the following code to deserialize the Networks XML

 private readonly string xml = @"<Networks computer=""DESKTOP-281OHFP"" GlobalFPPProxy=""GlobalFPPProxy"" GlobalForceLocalIP=""GlobalForceLocalIP"">
    <Controller Id=""100"" Name=""Falcon F4V3 1"">
        <network ComPort=""192.168.1.254"" BaudRate=""100"" NetworkType=""E131"" MaxChannels=""512""/>
        <network ComPort=""192.168.1.254"" BaudRate=""101"" NetworkType=""E131"" MaxChannels=""512""/>
        <network ComPort=""192.168.1.254"" BaudRate=""102"" NetworkType=""E131"" MaxChannels=""512""/>
        <network ComPort=""192.168.1.254"" BaudRate=""103"" NetworkType=""E131"" MaxChannels=""512""/>
        <network ComPort=""192.168.1.254"" BaudRate=""104"" NetworkType=""E131"" MaxChannels=""512""/>
        <network ComPort=""192.168.1.254"" BaudRate=""105"" NetworkType=""E131"" MaxChannels=""512""/>
    </Controller>
    <Controller Id=""1"" Name=""Serial_"">
        <network ComPort=""COM4"" BaudRate=""250000"" NetworkType=""DMX"" MaxChannels=""1""/>
    </Controller>
    <Controller Id=""2"" Name=""Null_"">
        <network NetworkType=""NULL"" MaxChannels=""1""/>
    </Controller>
</Networks>
 ";

        private void GenerateXML_Click(object sender, EventArgs e)
        {
            Networks result = new();
            string inputString = xml; 

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

            XmlSerializer serializer = new (typeof(Networks));
            StringReader rdr = new(doc.InnerXml);
            if (rdr is not null)
            {
                if (serializer is not null)
                    result = serializer.Deserialize(rdr) as Networks;
                    //richTextBox1.Text = result.Controller.ToString();
                rdr.Close();
                
            }
            
        }


Solution

  • This part [XmlArray(ElementName = "Controller")] [XmlArrayItem("NetworkController")] means there is NetworkController list of items inside Controller tag, like this

    <Controller ....>
      <NetworkController ....>....</NetworkController>
      <NetworkController ....>....</NetworkController>
      <NetworkController ....>....</NetworkController>
      .....
    </Controller>
    

    Which is not in your XML, You have to use [XmlElement(ElementName = "Controller")].

    The same thing with [XmlArray(ElementName = "network")] [XmlArrayItem("NetworkControllerNetwork")]

    Use [XmlElement(ElementName = "network")]

    And remove [XmlType("NetworkController")] from NetworkController class and [XmlType("NetworkControllerNetwork")] from NetworkControllerNetwork class

    This is the final result:

    [Serializable()]
    [XmlRoot("Networks")]
    public class Networks
    {
        [XmlElement(ElementName = "Controller")]
        public List<NetworkController> Controller { get; set; }
    
        [XmlAttribute("computer")]
        public string computer { get; set; }
    
        [XmlAttribute("GlobalFPPProxy")]
        public string GlobalFPPProxy { get; set; }
    
        [XmlAttribute("GlobalForceLocalIP")]
        public string GlobalForceLocalIP { get; set; }
    
    }
    
    public class NetworkController
    {
        //[XmlElement(ElementName = "Id")]
        [XmlAttribute(AttributeName = "Id")]
        public string Id { get; set; }
    
        //[XmlElement(ElementName = "Name")]
        [XmlAttribute(AttributeName = "Name")]
        public string Name { get; set; }
    
        [XmlElement(ElementName = "network")]
        public List<NetworkControllerNetwork> network { get; set; }
    
    }
    
    
    public class NetworkControllerNetwork
    {
        [XmlAttribute(AttributeName = "ComPort")]
        public string ComPort { get; set; }
    
        [XmlAttribute("BaudRate")]
        public int BaudRate { get; set; }
    
        [XmlAttribute("NetworkType")]
        public string NetworkType { get; set; }
    
        [XmlAttribute("MaxChannels")]
        public int MaxChannels { get; set; }
    
    }