4

I have the following XML snippet-

-<Row>
 <RowType Id="1"Label="Scotland">1985</RowType>
 <Year Id="11"Label="1994"/>
 <Value Id="123">18</Value>
 <Field Id="123"Label="Country">16</Field>
 <Field Id="123"Label="Soccer">Yes</Field>
</Row>
-<Row>
 <RowType Id="1"Label="England">1986</RowType>
 <Year Id="11"Label="1994"/>
 <Value Id="123">19</Value>
 <Field Id="123"Label="Country">16</Field>
 <Field Id="123"Label="Soccer">Yes</Field>
</Row>
-<Row>
 <RowType Id="1"Label="Wales">1987</RowType>
 <Year Id="11"Label="1994"/>
 <Value Id="123">20</Value>
 <Field Id="123"Label="Country">16</Field>
 <Field Id="123"Label="Soccer">Yes</Field>
</Row>

I am using XmlReader to retrieve specific data from it like so -

using (XmlReader reader = XmlReader.Create(new StringReader(xml)))
        {
            string country = "";
            string Year = "";
            string count = "";
            string tss= "";
            string tss2 = "";


            reader.MoveToContent();
            while (reader.Read())
            {

                reader.ReadToFollowing("RowType");
                country = reader.GetAttribute("Label");
                country = country.Replace("'", "");

                reader.ReadToFollowing("Year");
                Year = reader.GetAttribute("Label");

                reader.ReadToFollowing("Value");
                count = reader.ReadElementContentAsString();

                reader.ReadToFollowing("Field");
                tss = reader.GetAttribute("Label");

                reader.ReadToFollowing("Field");
                tss2 = reader.GetAttribute("Label");
            }
        }

This is working fine for the first iteration, however on the second, it retrieves the values from the third row in the XML, and continues to skip to the next row after the one it should be parsing.

How can I resolve this?

Ebikeneser
  • 2,582
  • 13
  • 57
  • 111

2 Answers2

5

Actually, your code is right; what is not right is the structure of the document. Or better, your code does not account for the specific structure of the document.

You can change that by adding the following bit:

XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
using (XmlReader reader = XmlReader.Create(new StringReader(xml), settings))

By default the XMLReader expects ConformanceLevel.Document and thus the file should have a structure like the following one:

<main>
<Row id="5">
 <RowType Id="1" Label="Scotland">1985</RowType>
 <Year Id="11" Label="1994"/>
 <Value Id="123">18</Value>
 <Field Id="123" Label="Country">16</Field>
 <Field Id="123" Label="Soccer">Yes</Field>
</Row>
<Row id="1">
 <RowType Id="1" Label="England">1986</RowType>
 <Year Id="11" Label="1994"/>
 <Value Id="123">19</Value>
 <Field Id="123" Label="Country">16</Field>
 <Field Id="123" Label="Soccer">Yes</Field>
</Row>
<Row id="4">
 <RowType Id="1" Label="Wales">1987</RowType>
 <Year Id="11" Label="1994"/>
 <Value Id="123">20</Value>
 <Field Id="123" Label="Country">16</Field>
 <Field Id="123" Label="Soccer">Yes</Field>
</Row>
</main>

I understand that the lack of separation between elements (e.g., Id="1"Label="Scotland" instead of Id="1" Label="Scotland") is a typo because separations have to exist in any case.

------------------- UPDATE

You report that your code does not deliver the expected result even after changing the conformance level. I have done a new test of your code and it works fine; at least, it iterates correctly. Thus, what I understand is that you want to retrieve different values than what you code does (it mixes app names, attributes and content).

Below you can see my own code (although I insist that yours iterates through the given information OK, too), which is more adaptable than yours; I am also including some comments in the parts where I think that you want to retrieve different information than what your code does. The basic idea is just retrieving information from the content (content), but your code takes it from anywhere.

        string path = @"XML file";
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.ConformanceLevel = ConformanceLevel.Fragment;
        using (XmlReader reader = XmlReader.Create(path, settings))
        {
            string country = "";
            string Year = "";
            string count = "";
            string tss = "";
            string tss2 = "";

            while (reader.ReadToFollowing("Row"))
            {
                XmlReader reader2 = reader.ReadSubtree();
                while (reader2.Read())
                {
                    if (reader2.NodeType == XmlNodeType.Element)
                    {
                        if (reader2.Name == "RowType")
                        {
                            country = reader2.GetAttribute("Label");
                            country = country.Replace("'", ""); //country_year = reader.ReadElementContentAsString(); -> "Scotland" -> 1985
                        }
                        else if (reader2.Name == "Year")
                        {
                            //IF XML IS -> <Year Id="11">1994<Year/>
                            //Then -> Year = reader2.GetAttribute("Label")
                            Year = reader2.GetAttribute("Label"); //-> 1994
                        }
                        else if (reader2.Name == "Value")
                        {
                            count = reader2.ReadElementContentAsString(); 
                        }
                        else if (reader2.Name == "Field")
                        {
                            if (reader2.GetAttribute("Label") == "Country")
                            {
                                tss = reader2.ReadElementContentAsString(); //I understand that this is what you want to read, instead the Label name
                            }
                            else if (reader2.GetAttribute("Label") == "Soccer")
                            {
                                tss2 = reader2.ReadElementContentAsString();//I understand that this is what you want to read, instead the Label name
                            }
                        }
                    }
                }
            }
        }

This should deliver what you are looking for; or, in the worst scenario, a much clear idea about how to deal with the XML reading. Also it might be a good thing to include a try...catch just in case; note that any error while reading/dealing with the variables would provoke the reading process to be immediately stopped.

varocarbas
  • 12,354
  • 4
  • 26
  • 37
  • Unfortunately I added your extra code and still not going over the XML in correct order... – Ebikeneser Jul 05 '13 at 12:56
  • I would have implemented the XML reading part differently than what you did. But I did test your code (after changing the ConformanceLevel) and worked fine!? I can change it (in the way I usually deal with this kind of XML reading situations) but not now because I am doing something else. I can come here back in a while and update my answer. – varocarbas Jul 05 '13 at 13:00
  • really appreciate your time, I have a lack of understanding with the 'readToFollowing' part and I guessed that was perhaps where the issue lay. – Ebikeneser Jul 05 '13 at 13:02
  • The first problem was the conformance level, which provoked a "crash" (= stop reading and get out the loop) after the first iteration. The other problem you have is that you are ignoring the main/secondary nodes and just using readToFollowing blindly. But, as said, after a quick test, your code seemed to work fine. Will test it in a while and include my own code. Not a problem, I take this kind of "small works" as relaxing pauses in my main, very-stressing work :) – varocarbas Jul 05 '13 at 13:05
  • I have updated my answer. Please, take a look at the new code (mainly to the assumptions) and let me know about your impressions. – varocarbas Jul 05 '13 at 14:56
  • Excellent update, I have applied the new logic at it does indeed bring back the correct values! Your latest syntax makes more sense to me in terms of breaking the XML down, instead of using the readToFollowing code. Much appreciated. – Ebikeneser Jul 05 '13 at 15:51
  • No problem. Your algorithm was adequate for this specific XML structure but quite inflexible; that's why I thought that it would be better to show you a different way to face the problem. – varocarbas Jul 05 '13 at 15:58
0

We can use LINQ to get this done if you want.

If you really want to read all the values from Xml into some variable....you can try something in similar lines...

        XElement po = XElement.Load(@"SoccerCup.xml");
        IEnumerable<XElement> childElements =
            from el in po.Elements()
            select el;
        foreach (XElement el in childElements)
        {
            var Year=el.Element("Year").Value;
            var country  = el.Element("country").Value;
            var count =el.Elemet("Value").Value;
            Console.WriteLine("Year: " + Year);
            Console.WriteLine("Country: " + country);
            Console.WriteLine("Count: " + count);
        }

Hope this helps...

gogreen
  • 65
  • 3
  • 8