0

I got a problem with the XMLReader in C#.

i got this Code:

private void countryXMLReader ()
        {
            XmlTextReader reader = new XmlTextReader("expenses.xml");
            List<string> twentyFour = new List<string>();
            while (reader.Read())
            {

                if (reader.Name.Equals("_24h"))
                {
                    twentyFour.Add(reader.Value);
                }

                if (reader.Name == "_14h")
                {
                    //MessageBox.Show(reader.Name);
                }


            }
        }

this is my XML-File:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<expenses>
    <country>
        <name>Germany</name>
        <ID>D</ID>
        <_24h>42</_24h>
        <_14h>28</_14h>
        <_8h>14</_8h>
        <overnight>100</overnight>
    </country>
    <country>
        <name>India</name>
        <ID>IND</ID>
            <_24h>30</_24h>
            <_14h>20</_14h>
            <_8h>10</_8h>
            <overnight>120</overnight>
    </country>
</expenses>

The ListItems are added to the list but the reader.Value is always empty.

How can I get this to work?

many thanks

Tobi

EDIT:

now I got the following code:

private void countryXMLReader () { List twentyFour = new List();

        XDocument doc = XDocument.Load(@"C:\Users\Bl!tz\Documents\Visual Studio 2010\Projects\MBG.SimpleWizard\Demo\bin\Debug\expenses.xml");
        twentyFour.AddRange(doc
                          .Elements("expenses")
                          .Descendants("country")
                          .Descendants("_24h")
                          .Select(i => i.Value)
                          .ToList());
    }

but it don't really got the values.

what can be my problem?

EDIT2:

this is the code I use:

private void countryXMLReader ()
        {
            List<string> twentyFour = new List<string>();

            XDocument doc = XDocument.Load(@"expenses.xml");
            twentyFour.AddRange(doc
                              .Elements("expenses")
                              .Descendants("country")
                              .Descendants("name")
                              .Descendants("ID")
                              .Descendants("_24h")
                              .Descendants("_14h")
                              .Descendants("_8h")
                              .Descendants("overnight")
                              .Select(i => i.Value)
                              .ToList());
        }

but the List.Count remains at 0. and I call this Method like this:

public Page1()
        {
            InitializeComponent();
            countryXMLReader();
        }

I also tested it with a button, but same result

user1414157
  • 53
  • 2
  • 10
  • Try setting the path to @"expenses.xml". And in Visual Studio set the "Copy to Output Directory" property of the file expenses.xml to "Copy always" (I presume that you added expenses.xml to your project). – Ivan Golović Jul 03 '12 at 09:34
  • I've set the property and changed the path, but the list still is empty – user1414157 Jul 03 '12 at 10:55
  • It's working on the sample XML code that you have provided, make sure that XML in file has the same structure as the one posted in question. Can you put the XML file on web (if it doesn't contain any sensitive data)? – Ivan Golović Jul 03 '12 at 11:07
  • yes I can put it on the web but it is really big. about 2000 lines :-) there are only more countries with the same nodes and attributes. – user1414157 Jul 03 '12 at 11:15
  • Put it on the web and post the link, I'll give it a try at my computer. – Ivan Golović Jul 03 '12 at 11:26
  • could you give me a host where I can upload it? :-) – user1414157 Jul 03 '12 at 11:37
  • this should be run: https://rapidshare.com/files/2693261564/expenses.xml – user1414157 Jul 03 '12 at 11:45
  • I tried with the file you have posted on web, it works, it gets 250 values in the list. Try to create a simple demo console application and add XML file to the project, then provide it as input to XDocument.Load as we have described, it should work... – Ivan Golović Jul 03 '12 at 16:54
  • this also didn't run. what else could it be? – user1414157 Jul 04 '12 at 05:39
  • You shouldn't use .Descendants("_14h").Descendants("_8h").Descendants("overnight") if you want values of elements named "_24". Besides that, elements named "_14", "_8h" and "overnight" are not descendants of element "_24". – Ivan Golović Jul 04 '12 at 05:59
  • ok. but also without Descendants("_14h").Descendants("_8h").Descendants("overnight").Descendants("ID").Descendants("_24h") I don't get filled the list. At the moment I only got the .Element("expenses") .Descendants("country") .Descendants("name") – user1414157 Jul 04 '12 at 06:12
  • I changed the answer, it puts all the name, _14h, _24h element values into their respective lists. Elements name, ID, _14h, _24h, _8h, overnight are on the same level and all of them are descendant elements of element country. – Ivan Golović Jul 04 '12 at 06:30
  • it works :-) but I don't know why. Last Question. How can I access the values of the Lists? array-like with the index? – user1414157 Jul 04 '12 at 06:35
  • Yes, individual values of the list can be retrieved using index, besides that, many other operations can be performed on list using extension methods. You should read some tutorials on XML and XDocument documentation on MSDN, it'll be all right once you get the hang of it :) – Ivan Golović Jul 04 '12 at 06:42
  • I'm glad to help, I added some code to the answer to show how you can process each of the country elements individually and access it's child elements. – Ivan Golović Jul 04 '12 at 06:53

2 Answers2

0

Try this code that uses XmlDocument and XPath expression:

        string s = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><expenses>    <country>        <name>Germany</name>        <ID>D</ID>        <_24h>42</_24h>        <_14h>28</_14h>        <_8h>14</_8h>        <overnight>100</overnight>    </country>    <country>        <name>India</name>        <ID>IND</ID>            <_24h>30</_24h>            <_14h>20</_14h>            <_8h>10</_8h>            <overnight>120</overnight></country></expenses>";

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

        XmlNode rootNode = doc.SelectSingleNode(@"/expenses");
        var nodes24 = rootNode.SelectNodes(@"country/_24h");
        var nodes14 = rootNode.SelectNodes(@"country/_14h");

        List<string> twentyFour = new List<string>();
        twentyFour.AddRange(nodes24
                            .Cast<XmlNode>()
                            .Select(i => i.InnerText)
                            .ToArray());

You can also try the System.Xml.Linq approach which is recommended and newer than XmlDocument but requires NET version higher than 3.0:

        List<string> names = new List<string>();
        List<string> twentyFour = new List<string>();
        List<string> fourteen = new List<string>();

        XDocument doc = XDocument.Load(@"expenses.xml");

        var elements = doc
          .Root
          .Descendants("country");

        names.AddRange(elements
                            .Descendants("name")
                            .Select(i => i.Value)
                            .ToList());

        twentyFour.AddRange(elements
                            .Descendants("_24h")
                            .Select(i => i.Value)
                            .ToList());

        fourteen.AddRange(elements
                            .Descendants("_14h")
                            .Select(i => i.Value)
                            .ToList());

        // You can process each country element individually like this
        foreach (XElement el in elements)
        {
            string name = el.Element("name").Value;
            string _24h = el.Element("_24h").Value;
            string _14h = el.Element("_14h").Value;
        }
Ivan Golović
  • 8,732
  • 3
  • 25
  • 31
  • Which will be better? or where is the difference between these to alternatives. this XML-File is just a snippet of my whole XML. sorry for that, so it will be a really long string which I have to put to my code. – user1414157 Jul 03 '12 at 08:29
  • I changed XElement to XDocument (XElement is for XML fragments while XDocument is for entire documents). Here is the answer with differences between XDocument and XmlDocument: http://stackoverflow.com/questions/1542073/xdocument-or-xmldocument According to that, XDocument is a better approach (unless you're using NET version 3.0. or lower, in that case XDocument is not available). – Ivan Golović Jul 03 '12 at 08:38
  • but I can't use XDocument because I have to copy the whole XML into a string. So I have to change a arbitrary value in the string and not in the XML. Do I have this right? – user1414157 Jul 03 '12 at 08:55
  • You can read XML content directly from file, for example: `XDocument doc = XDocument.Load(@"C:\test.xml");` – Ivan Golović Jul 03 '12 at 09:07
0

For giving string value of element content in XmlReader use ReadElementContentAsString().

instead of

twentyFour.Add(reader.Value);

use

twentyFour.Add(reader.ReadElementContentAsString());
Ria
  • 10,237
  • 3
  • 33
  • 60