Search code examples
c#xml-parsingxmlreader

reading xml file with XmlReader reads only the first element


I'm having problems reading child elements with XmlReader.

My xml file

<?xml version="1.0" encoding="UTF-8"?>
<WateringZones>
   <WateringZone>
      <Enabled>True</Enabled>
      <Name>Calle 1</Name>
      <Relay>1</Relay>
      <Monday>True</Monday>
      <Tuesday>True</Tuesday>
      <Wednesday>True</Wednesday>
      <Thursday>True</Thursday>
      <Friday>True</Friday>
      <Saturday>True</Saturday>
      <Sunday>False</Sunday>
      <WateringTurns>
         <WateringTurn>
            <Enabled>True</Enabled>
            <Name>Turno 1</Name>
            <Minutes>5</Minutes>
         </WateringTurn>
         <WateringTurn>
            <Enabled>True</Enabled>
            <Name>Turno 2</Name>
            <Minutes>5</Minutes>
         </WateringTurn>
         <WateringTurn>
            <Enabled>True</Enabled>
            <Name>Turno 3</Name>
            <Minutes>5</Minutes>
         </WateringTurn>
         <WateringTurn>
            <Enabled>False</Enabled>
            <Name>Turno 4</Name>
            <Minutes>0</Minutes>
         </WateringTurn>
         <WateringTurn>
            <Enabled>False</Enabled>
            <Name>Turno 5</Name>
            <Minutes>0</Minutes>
         </WateringTurn>
         <WateringTurn>
            <Enabled>False</Enabled>
            <Name>Turno 6</Name>
            <Minutes>0</Minutes>
         </WateringTurn>
         <WateringTurn>
            <Enabled>False</Enabled>
            <Name>Turno 7</Name>
            <Minutes>0</Minutes>
         </WateringTurn>
         <WateringTurn>
            <Enabled>False</Enabled>
            <Name>Turno 8</Name>
            <Minutes>0</Minutes>
         </WateringTurn>
      </WateringTurns>
   </WateringZone>
   <WateringZone>
      <Enabled>True</Enabled>
      <Name>Calle 2</Name>
      <Relay>2</Relay>
      <Monday>False</Monday>
      <Tuesday>True</Tuesday>
      <Wednesday>False</Wednesday>
      <Thursday>False</Thursday>
      <Friday>True</Friday>
      <Saturday>True</Saturday>
      <Sunday>False</Sunday>
      <WateringTurns>
         <WateringTurn>
            <Enabled>True</Enabled>
            <Name>Turno 1</Name>
            <Minutes>5</Minutes>
         </WateringTurn>
         <WateringTurn>
            <Enabled>False</Enabled>
            <Name>Turno 2</Name>
            <Minutes>0</Minutes>
         </WateringTurn>
         <WateringTurn>
            <Enabled>False</Enabled>
            <Name>Turno 3</Name>
            <Minutes>0</Minutes>
         </WateringTurn>
         <WateringTurn>
            <Enabled>False</Enabled>
            <Name>Turno 4</Name>
            <Minutes>0</Minutes>
         </WateringTurn>
         <WateringTurn>
            <Enabled>False</Enabled>
            <Name>Turno 5</Name>
            <Minutes>0</Minutes>
         </WateringTurn>
         <WateringTurn>
            <Enabled>False</Enabled>
            <Name>Turno 6</Name>
            <Minutes>0</Minutes>
         </WateringTurn>
         <WateringTurn>
            <Enabled>False</Enabled>
            <Name>Turno 7</Name>
            <Minutes>0</Minutes>
         </WateringTurn>
         <WateringTurn>
            <Enabled>False</Enabled>
            <Name>Turno 8</Name>
            <Minutes>0</Minutes>
         </WateringTurn>
      </WateringTurns>
   </WateringZone>
</WateringZones>

and I'm trying to read this file with the following code:

    private void LoadFromXml(string filename)
    {
        try
        {
            int sprinkler = 0;
            int sprinklerTurn = 0;

            // Create an XML reader for this file.
            using (XmlReader reader = XmlReader.Create(filename))
            {
                while (reader.Read())
                {
                    // Only detect start elements.
                    if (reader.IsStartElement())
                    {
                        while (reader.Read())
                        {
                            Console.WriteLine(reader.NodeType + ": " + reader.LocalName + "\n");

                            if (reader.NodeType.Equals(XmlNodeType.Element))
                            {
                                // Get element name and switch on it.
                                switch (reader.LocalName)
                                {
                                    case "WateringZone":
                                        {
                                            sprinklerTurn = 0;

                                            // Detect this element.
                                            if (reader.ReadToFollowing("Enabled"))
                                            {
                                                var enabled = reader.ReadElementContentAsString();
                                                wateringScheluder.WateringZones[sprinkler].Enabled = Convert.ToBoolean(enabled);
                                            }

                                            if (reader.ReadToFollowing("Name"))
                                            {
                                                wateringScheluder.WateringZones[sprinkler].Name = reader.ReadElementContentAsString();
                                            }

                                            if (reader.ReadToFollowing("Relay"))
                                            {
                                                wateringScheluder.WateringZones[sprinkler].Relay = reader.ReadElementContentAsInt();
                                            }

                                            if (reader.ReadToFollowing("Monday"))
                                            {
                                                var enabled = reader.ReadElementContentAsString();
                                                wateringScheluder.WateringZones[sprinkler].Monday = Convert.ToBoolean(enabled);
                                            }

                                            if (reader.ReadToFollowing("Tuesday"))
                                            {
                                                var enabled = reader.ReadElementContentAsString();
                                                wateringScheluder.WateringZones[sprinkler].Tuesday = Convert.ToBoolean(enabled);
                                            }

                                            if (reader.ReadToFollowing("Wednesday"))
                                            {
                                                var enabled = reader.ReadElementContentAsString();
                                                wateringScheluder.WateringZones[sprinkler].Wednesday = Convert.ToBoolean(enabled);
                                            }

                                            if (reader.ReadToFollowing("Thursday"))
                                            {
                                                var enabled = reader.ReadElementContentAsString();
                                                wateringScheluder.WateringZones[sprinkler].Thursday = Convert.ToBoolean(enabled);
                                            }

                                            if (reader.ReadToFollowing("Friday"))
                                            {
                                                var enabled = reader.ReadElementContentAsString();
                                                wateringScheluder.WateringZones[sprinkler].Friday = Convert.ToBoolean(enabled);
                                            }

                                            if (reader.ReadToFollowing("Saturday"))
                                            {
                                                var enabled = reader.ReadElementContentAsString();
                                                wateringScheluder.WateringZones[sprinkler].Saturday = Convert.ToBoolean(enabled);
                                            }

                                            if (reader.ReadToFollowing("Sunday"))
                                            {
                                                var enabled = reader.ReadElementContentAsString();
                                                wateringScheluder.WateringZones[sprinkler].Sunday = Convert.ToBoolean(enabled);
                                            }

                                            // Esperamos el signiente springle
                                            sprinkler++;
                                        }
                                        break;
                                    case "WateringTurn":
                                        {
                                            if (reader.ReadToFollowing("Enabled"))
                                            {
                                                var enabled = reader.ReadElementContentAsString();
                                                wateringScheluder.WateringZones[sprinkler].WateringTurns[sprinklerTurn].Enabled = Convert.ToBoolean(enabled);
                                            }
                                            if (reader.ReadToFollowing("Name"))
                                            {
                                                wateringScheluder.WateringZones[sprinkler].WateringTurns[sprinklerTurn].Name = reader.ReadElementContentAsString();
                                            }
                                            if (reader.ReadToFollowing("Minutes"))
                                            {
                                                wateringScheluder.WateringZones[sprinkler].WateringTurns[sprinklerTurn].Minutes = reader.ReadElementContentAsInt();
                                            }

                                            // Esperamos el siguiente turno
                                            sprinklerTurn++;
                                        }
                                        break;
                                    default:
                                        // ignore other nodes
                                        break;
                                }
                            }
                        }
                    }
                }
            }
        }
        catch (Exception e)
        {
            MessageBox.Show("No se pudo cargar, el mensaje de error fue :" + e.Message);
        }
    }

But it only reads the first <WateringZone> and then reader.Read() returns false, isn't supposed to continue reading <WateringTurns> ?


Solution

  • Here is solution using combination of XmlReader and Xml Linq.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Linq;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            const string FILENAME = @"c:\temp\test.xml";
            static void Main(string[] args)
            {
                XmlReader reader = XmlReader.Create(FILENAME);
                while (!reader.EOF)
                {
                    if (reader.Name != "WateringZone")
                    {
                        reader.ReadToFollowing("WateringZone");
                    }
                    if (!reader.EOF)
                    {
                        XElement wateringZone = (XElement)XElement.ReadFrom(reader);
                        WateringZone newZone = new WateringZone();
                        WateringZone.wateringZones.Add(newZone);
                        newZone.enabled = (Boolean)wateringZone.Element("Enabled");
                        newZone.name = (string)wateringZone.Element("Name");
                        newZone.relay = (int)wateringZone.Element("Relay");
                        newZone.monday = (Boolean)wateringZone.Element("Monday");
                        newZone.tuesday = (Boolean)wateringZone.Element("Tuesday");
                        newZone.wednesday = (Boolean)wateringZone.Element("Wednesday");
                        newZone.thursday = (Boolean)wateringZone.Element("Thursday");
                        newZone.friday = (Boolean)wateringZone.Element("Friday");
                        newZone.saturday = (Boolean)wateringZone.Element("Saturday");
                        newZone.sunday = (Boolean)wateringZone.Element("Sunday");
                        newZone.wateringTurns = wateringZone.Descendants("WateringTurn").Select(x => new WateringTurn() {
                            enabled = (Boolean)x.Element("Enabled"),
                            name = (string)x.Element("Name"),
                            minutes = (int)x.Element("Minutes")
                        }).ToList();
                    }
                }
    
            }
        }
        public class WateringZone
        {
            public static List<WateringZone> wateringZones = new List<WateringZone>();
            public Boolean enabled { get;set;}
            public string name { get;set;}
            public int relay { get;set;}
            public Boolean monday { get;set;}
            public Boolean wednesday { get; set;}
            public Boolean thursday { get; set;}
            public Boolean tuesday { get; set;}
            public Boolean friday { get; set;}
            public Boolean saturday { get; set;}
            public Boolean sunday { get; set;}
            public List<WateringTurn> wateringTurns { get; set; }
    
        }
        public class WateringTurn
        {
             public Boolean enabled {get;set;}
             public string name { get;set;}
             public int minutes { get; set; }
        }
    }