Ebikeneser
Ebikeneser

Reputation: 2364

Xml reader skipping values

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?

Upvotes: 4

Views: 3752

Answers (2)

user2480047
user2480047

Reputation:

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.

Upvotes: 5

gogreen
gogreen

Reputation: 75

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...

Upvotes: 0

Related Questions