0

I am fairly new to C#. I searched the web for the last days to find a solution for my problem, but all I can find is too complex. What I want to do: Read a simple XML file and save eache value into a variable I can use in my C# program. This is the XML:

<?xml version="1.0" encoding="utf-8"?>
<Settings>
  <General>
    <Option1>66</Option1>
    <Option2>78</Option2>
    <Checkbox1>False</Checkbox1>
  </General>
  <Advanced>
    <AdvOption1>22</AdvOption1>
  </Advanced>
</Settings>

So, to make clear what I want to achieve: I want to save "66", "78" and "False" into variables. There will never be 2 XML Nodes with the same name. I can't really show any C# code, cause I tried so many different snippets, but they all used loops cause it was reading multiple "titles" or "authors" for example. I just think its too simple, thats why there isn't anything on the web :(

user353gre3
  • 2,747
  • 4
  • 24
  • 27
jayrrr
  • 159
  • 1
  • 2
  • 14

3 Answers3

2

There are several ways to achieve what you are asking to do. Here is one sample using XLinq. You can also use an xpath based solution (see this Link for more info).

The solution queries the XML file using linq style syntax, note that there are some decisions you need to make about dealing with missing sections or duplicate section, I chose a solution but it's up to you to make sure it fits your applications need.

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

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            // Get the XML doc from a file, similarly you can get it from a string or stream.
            var doc = XDocument.Load("file.xml");

            // Use linq style to get to the first Settings element or throw
            var settings = doc.Elements("Settings").Single().Elements();

            // Get root nodes for the settings type, if there is more than one ignore the rest and grab the first.
            // Change the logic to throw or combine to match the rules for your app
            var generalOptions = settings.FirstOrDefault(e => e.Name.LocalName == "General");
            var advancedOptions = settings.FirstOrDefault(e => e.Name.LocalName == "Advanced");

            var generalSettings = ExtractOptions(generalOptions);
            var advancedSettings = ExtractOptions(advancedOptions);
        }

        private static Settings ExtractOptions(XElement rootElement)
        {
            var settings = new Settings();

            if (rootElement != null)
            {
                var elements = rootElement.Elements();

                settings.Options = elements.Where(e => e.Name.LocalName.IndexOf("Option", StringComparison.OrdinalIgnoreCase) >= 0)
                                           .Select(e => int.Parse(e.Value))
                                           .ToArray();

                settings.CheckBoxes = elements.Where(e => e.Name.LocalName.StartsWith("CheckBox", StringComparison.OrdinalIgnoreCase))
                                              .Select(e => bool.Parse(e.Value))
                                              .ToArray();
            }

            return settings;
        }

        public class Settings
        {
            public int[] Options { get; set; }
            public bool[] CheckBoxes { get; set; }
        }
    }
}
Yishai Galatzer
  • 8,791
  • 2
  • 32
  • 41
2

Try to use something like this:

int opt1, opt2, advOpt1;
bool check;

XmlDocument doc = new XmlDocument();
doc.Load("YourXMLFile.xml");

opt1 = Convert.ToInt32(doc.SelectSingleNode("Settings/General/Option1").InnerText);
opt2 = Convert.ToInt32(doc.SelectSingleNode("Settings/General/Option2").InnerText);
check = Convert.ToBoolean(doc.SelectSingleNode("Settings/General/Checkbox1").InnerText);
advOpt1 = Convert.ToInt32(doc.SelectSingleNode("Settings/Advanced/AdvOption1").InnerText);
Gleb
  • 1,412
  • 1
  • 23
  • 55
0

While you could hack it with regex etc, you're going to be better off in the long run if you just parse the XML properly.

Take a look at XDocument. Here is an example of parsing an XML formatted web response from https://github.com/slicify/nslicify

XML

<BidInfo xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://secure.slicify.com">
  <BidID>32329</BidID>
  <BookingID>131179</BookingID>
  <Active>true</Active>
  <MaxPrice>0.01</MaxPrice>
  <MinECU>20</MinECU>
  <MinRAM>1024</MinRAM>
  <Country/>
  <Bits>64</Bits>
  <Deleted>false</Deleted>
  <IncLowBW>false</IncLowBW>
  <ScriptID>153</ScriptID>
  <UserData/>
</BidInfo>

Parser

    private BidInfo BidInfoParser(XDocument doc)
    {
        BidInfo info = null;

        //get the first record in the result set
        XContainer c1 = (XContainer)(doc);
        XContainer c2 = (XContainer)(c1.FirstNode);

        //loop through fields
        foreach (XNode node in c2.Nodes())
        {
            XElement el = (XElement)node;
            string key = el.Name.LocalName;
            string value = el.Value;

            //little hack to only set BidInfo if there are some values
            if(info == null)
                info = new BidInfo();

            if (key.Equals("Active", StringComparison.InvariantCultureIgnoreCase))
                info.Active = Convert.ToBoolean(value);
            else if (key.Equals("BidID", StringComparison.InvariantCultureIgnoreCase))
                info.BidID = Convert.ToInt32(value);
            else if (key.Equals("Bits", StringComparison.InvariantCultureIgnoreCase))
                info.Bits = Convert.ToInt32(value);
            else if (key.Equals("BookingID", StringComparison.InvariantCultureIgnoreCase))
                info.BookingID = Convert.ToInt32(value);
            else if (key.Equals("Country", StringComparison.InvariantCultureIgnoreCase))
                info.Country = value;
            else if (key.Equals("MaxPrice", StringComparison.InvariantCultureIgnoreCase))
                info.MaxPrice = Convert.ToDecimal(value);
            else if (key.Equals("MinECU", StringComparison.InvariantCultureIgnoreCase))
                info.MinECU = Convert.ToInt32(value);
            else if (key.Equals("MinRAM", StringComparison.InvariantCultureIgnoreCase))
                info.MinRAM = Convert.ToInt32(value);
            else if (key.Equals("Deleted", StringComparison.InvariantCultureIgnoreCase))
                info.Deleted = Convert.ToBoolean(value);
            else if (key.Equals("IncLowBW", StringComparison.InvariantCultureIgnoreCase))
                info.IncludeLowBandwidth = Convert.ToBoolean(value);
            else if (key.Equals("scriptID", StringComparison.InvariantCultureIgnoreCase))
                info.ScriptID = Convert.ToInt32(value);
            else if (key.Equals("userdata", StringComparison.InvariantCultureIgnoreCase))
                info.UserData = value;
            else
                throw new Exception("Unknown tag in XML:" + key + " = " + value);
        }
        return info;
    }

    /// <summary>
    /// Contains information about this bid.
    /// </summary>
    public class BidInfo
    {
        public int BidID { get; set; }
        public int BookingID { get; set; }
        public bool Active { get; set; }
        public decimal MaxPrice { get; set; }
        public int MinECU { get; set; }
        public int MinRAM { get; set; }
        public string Country { get; set; }
        public int Bits { get; set; }
        public bool Deleted { get; set; }
        public bool IncludeLowBandwidth { get; set; }
        public int ScriptID { get; set; }
        public string UserData { get; set; }
    }
steve cook
  • 3,116
  • 3
  • 30
  • 51