0

I have a XML structure (only a snippet) as follows:

<ttOutput>
    <ttOutputRow>
       <cKey>key</cKey>
       <cValue>value</cValue>
    </ttOutputRow>
    <ttOutputRow>
       <cKey>findMe</cKey>
       <cValue>value</cValue>
    </ttOutputRow>
    <ttOutputRow>
       <cKey>key</cKey>
       <cValue>value</cValue>
     </ttOutputRow>
</ttOutput>

For this I want to use XMLReader to keep memory low. I'm looking for cValue if cKey is findMe. How can I get this value?

This is what I tried:

using (var stream = new StreamReader(path))
using (XmlReader reader = XmlReader.Create(stream))
{
    while(reader.Read())
    {
        if (reader.IsStartElement())
        {
            Console.WriteLine (reader.Name);
            if (reader.Name == "ttOutputRow") {
                XmlReader subreader = reader.ReadSubtree ();
                while (subreader.Read ()) {
                    if (subreader.Name == "cKey" && subreader.Value == "findMe") {
                        subreader.ReadToNextSibling ("cValue");
                        Console.WriteLine ("found");
                    }
                }
            }
        }
    }
}

Perhaps I can use ReadToDescendant(String) or ReadSubtree() here, but I don't know how to use it correctly.

Edit:

This seems to be another option using ReadToDescendant:

while(reader.Read())
{
    reader.ReadToFollowing ("ttOutputRow");
    do {
        if (reader.ReadToDescendant ("cKey")) {
            if (reader.ReadInnerXml() == "findMe") {
                reader.ReadToNextSibling ("cValue");
                Console.WriteLine ("found");
            }
        }
    } while (reader.ReadToFollowing ("ttOutputRow"));
}

I also found out that you can only use ReadInnerXml() one time.

testing
  • 19,681
  • 50
  • 236
  • 417

1 Answers1

1

Use subreader.Value when the reader points to the child text node instead of pointing to the parent element node. You can also use ReadInnerXml() to get text value of an element node provided that the element doesn't have child element, for example :

if (subreader.Name == "cKey" && subreader.ReadInnerXml() == "findMe") 
{
    subreader.ReadToNextSibling("cValue");
    Console.WriteLine ("found: {0}", subreader.ReadInnerXml());
    //output:
    //found: value
}
har07
  • 88,338
  • 12
  • 84
  • 137
  • Does using a *subreader* increases the need for memory because two readers are active at the same time? Do you think reading the file directly instead of using a `StreamReader` is better (more memory efficient)? I've updated my question with an example using `ReadToDescendant`. Is using `ReadToDescendant` or `ReadSubtree` better? Is there a possibility to stack `ReadInnerXml` into a stream so that not everything is hold in memory? – testing May 07 '15 at 09:10
  • Should I check for `reader.NodeType == XmlNodeType.Element`? Or isn't this necessary? – testing May 07 '15 at 10:24
  • 1
    Since most of the XmlReader methods being used in your code receives element name as parameter -f.e `ReadToDescendant("elementName")-, check for `NodeType` isn't necessary I think -the type in that case must be `XmlNodeType.Element`. – har07 May 07 '15 at 13:00
  • Thanks for the information. Do you had a chance to look on my other questions too? – testing May 07 '15 at 13:05