Iterating through xmltextreader

487 views Asked by At

I have a xml in the following format.

<?xml version="1.0" encoding="UTF-8" standalone= "yes"?>
<rss>
  <report name="rpt1">
    <title>AAA</title>
    <image></image>
    <weblink></weblink>
    <pdflink></pdflink>
    <pdfsize></pdfsize>
  </report>
  <report name="rpt2">
    <title>BBB</title>
    <image>CCC</image>
    <weblink>DDD</weblink>
    <pdflink>EEE</pdflink>
    <pdfsize>FFF</pdfsize>
  </report>
</rss>

Now I want to iterate this xml and get the report node and from there get childnodes like title/pdflink/size etc which would be thru. looping using for loop.

I want to use xmltextreader to accomplish this. I tried using while but I get only 1 loop after iterating. I don't know why. If thru for loop how do I iterate like,
for(loop when reader.element("reports)){} and then get the rest of the nodes and put them in an array or list or so. Once I get them stored in list I would want to display them in a feed.

What is the best way to do this? Pls, help.

1

There are 1 answers

0
Matt Klinker On

In my case I was worried about the performance of loading a large document. What I have done is define a constructor on my objects to receive a XmlReader and hydrate - passing the reader back after it reaches a complete node.

This allows me to yield a populated object back as IEnumerable for each object as it's being read. Then I launch a new Task/Thread to handle processing that individual item and go back to processing the file.

private IEnumerable<Report> readReports(Stream reader)
{
    var settings = new XmlReaderSettings();
    settings.IgnoreWhitespace = true;
    var xmlReader = XmlReader.Create(reader, settings);
    xmlReader.MoveToContent();
    xmlReader.Read();
    while (!xmlReader.EOF)
    {
        if (xmlReader.Name.ToUpper() == "report") 
            yield return new Report(xmlReader);

        xmlReader.Read();
    }
}

public Report(XmlReader reader) : this()
{
    reader.MoveToContent();
    if (reader.IsEmptyElement)
    {
        reader.Read();
        return;
    }

    reader.Read();
    while (!reader.EOF)
    {
        if (reader.IsStartElement())
        {
            switch (reader.Name.ToLower())
            {
                case "order_id":
                    this.OrderId = reader.ReadElementContentAsString();
                    break;
                    // abreviated the rest of the fields
                default:
                    reader.Skip();
                    break;
            }
        }
        else if (reader.Name.ToLower() == "report") //this watches for the end element of the container and returns after populating all properties
            return;
    }
}

I would definitly appreciate any feedback from the rest of the community, if there is a better approach or if there are any errors here please let me know.