3

This is an XML example I want to deserialize and use in a Desktop App, where the user could insert an XML like this one:

   <Settings>
        <FileName>C:\Users\myniceuser\Desktop\hello.xmldoc</FileName>
        <Zones>
                <Row1>
                        <Address>2</Address>strong text
                        <Zone>2</Zone>
                        <Installed>True</Installed>
                </Row1>
                <Row2>
                        <Address>3</Address>
                        <Zone>2</Zone>
                        <Installed>True</Installed>
                </Row2>
                <Row3>
                        <Address>4</Address>
                        <Zone>2</Zone>
                        <Installed>True</Installed>
                </Row3>
                <Row4>
                        <Address>5</Address>
                        <Zone>2</Zone>
                        <Installed>True</Installed>
                </Row4>
        </Zones>
        <Network_IP>010.000.008.072</Network_IP>
        <Ethernet_Enable>true</Ethernet_Enable>
        <Language>1</Language>
</Settings>

The class I implemented is this one:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace MyApp.Models
{
    [XmlRoot(ElementName = "Settings")]
    public class XML_Settings
    {

        [XmlElement(ElementName = "FileName")]
        public string FileName { get; set; }


        //[XmlElement(ElementName = "Zones")]
        [XmlElement(ElementName ="Zones")]
        public Zones_Points[] Zones_Points { get; set; }

        [XmlElement(ElementName = "Network_IP")]
        public string NetworkIP { get; set; }

        [XmlElement(ElementName = "Ethernet_Enable")]
        public bool EthernetEnable { get; set; }

        [XmlElement(ElementName = "Language")]
        public int Language { get; set; }
}
    [XmlRoot(ElementName = "")]
    public partial class Zones_Points
    {
        [XmlElement(ElementName ="Address")]
        public int Address { get; set; }

        [XmlElement(ElementName ="Zone")]
        public int PointZone { get; set; }

        [XmlElement(ElementName ="Installed")]
        public bool Installed { get; set; }

}
}

I deserialize like this:

Models.XML_Settings inputted_xml = new();
using StreamReader stream_xml = new StreamReader(xmlfile_path, CodePagesEncodingProvider.Instance.GetEncoding(1253));
                
XmlSerializer serializer = new XmlSerializer(typeof(Models.XML_Settings));

try
{
 Models.XML_Settings input = (Models.XML_GR6500)serializer.Deserialize(stream_xml);
 }
 catch (Exception exception)
 {
 MessageBox.Show(exception.Message);
 }

I want my app to input files in XML like this one, and convert their data to a class that i can use.

The object "input" created by the Deserialization got every data correct, except the Zones, those that in XML have the "Row" tags. Those "rows" could every time be more or less that 4.

What can I do to have the items with the row tags deserialized and inputted into a Zones_Points list or array?

GSmyrlis
  • 43
  • 1
  • 7
  • 1
    Why are the tags numbered? – Fildor Oct 11 '21 at 09:33
  • 3
    Honestly, whoever designed that xml layout (re the ``, `` etc) needs talking to; that's just a terrible idea (xml is already positional, at least for elements (less-so attributes)), and it is going to make your life hard; you're going to have to do a lot of stuff the hard way as a result. Is there any possibility, for example, of running this through a transformation (perhaps xslt, although that isn't "in fashion" currently), to something that just uses ``? – Marc Gravell Oct 11 '21 at 09:42
  • 2
    Marc touched the sore spot, your xml doesnt fit the `XmlSerializer`. The default serializer [doesn't support wildcard names](https://stackoverflow.com/questions/10718352/xml-deserialization-xmlelement-wildcard-in-elementname). [Preprocess the data](https://stackoverflow.com/questions/34087941/how-can-i-deserialize-any-xml-element-to-a-list-via-the-xmlserializer) or implement a custom serializer. – Fixation Oct 11 '21 at 09:58
  • Thanks for answering guys! I don't make the XML files. They are produced by an old software, but I need my app to be able to input the data from those. Should I rename every Row* to Row when reading the file? And after that what should I do? – GSmyrlis Oct 11 '21 at 10:13
  • https://stackoverflow.com/a/67035760/5045688 - Use custom XmlReader – Alexander Petrov Oct 11 '21 at 10:39

1 Answers1

3

Use IXmlSerializable

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.Schema;
using System.Xml.Linq;

namespace ConsoleApplication2
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XmlReader reader = XmlReader.Create(FILENAME);
            XmlSerializer serializer = new XmlSerializer(typeof(XML_Settings));
            XML_Settings settings = (XML_Settings)serializer.Deserialize(reader);
  
        }
    }
    [XmlRoot("Settings")]
    public class XML_Settings
    {


        [XmlElement(ElementName = "FileName")]
        public string FileName { get; set; }

        [XmlElement(ElementName = "Zones")]
        public Zones_Points Zones_Point { get; set; }
        [XmlElement(ElementName = "Network_IP")]
        public string NetworkIP { get; set; }
        [XmlElement(ElementName = "Ethernet_Enable")]
        public bool EthernetEnable { get; set; }
        [XmlElement(ElementName = "Language")]
        public int Language { get; set; }
    }
    public partial class Zones_Points : IXmlSerializable
    {
        // Xml Serialization Infrastructure
        [XmlElement(ElementName = "Zones")]
        public List<Zones_Point> Points { get; set; }

        public void WriteXml(XmlWriter writer)
        {
        }

        public void ReadXml(XmlReader reader)
        {

            XElement zones = (XElement)XElement.ReadFrom(reader);
            Points = new List<Zones_Point>();
            foreach (XElement row in zones.Elements())
            {
                Zones_Point Point = new Zones_Point();
                Points.Add(Point);
                Point.Address = (int)row.Element("Address");
                Point.PointZone = (int)row.Element("Zone");
                Point.Installed = (Boolean)row.Element("Installed");
            }

        }

        public XmlSchema GetSchema()
        {
            return (null);
        }
    }
    public partial class Zones_Point
    {
        [XmlElement(ElementName = "Address")]
        public int Address { get; set; }
        [XmlElement(ElementName = "Zone")]
        public int PointZone { get; set; }
        [XmlElement(ElementName = "Installed")]
        public bool Installed { get; set; }
    }
}
jdweng
  • 33,250
  • 2
  • 15
  • 20