1

I have a XML file like that:

    <key>businessAddress</key>
    <string>Moka</string>
    <key>businessName</key>
    <string>Moka address</string>
    <key>Id</key>
    <string>39</string>
    <key>Cat</key>
    <string>216</string>
    <key>deals</key>

I want to read the next <string> value if the key is Id

So what I did is this:

XmlTextReader reader = new XmlTextReader(file);

while (reader.Read())
{
    if (reader.Value.Equals("Id"))
    {
        reader.MoveToNextAttribute
    }  
}

but I didn't succeed.

Thanks for help

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
user2274204
  • 315
  • 3
  • 6
  • 18

3 Answers3

1

You could use a boolean flag to indicate whether you should read the value of the next element:

bool shouldReadId = false;
while (reader.Read())
{
    if (reader.NodeType == XmlNodeType.Text && shouldReadId)
    {
        Console.WriteLine(reader.Value); // will print 39
        shouldReadId = false;
    }

    if (reader.Value.Equals("Id"))
    {
        // indicate that we should read the value of the next element
        // in the next iteration
        shouldReadId = true;
    }
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
1

I'd like to point that XmlTextReader is basically replaced with XmlReader:

Starting with the .NET Framework 2.0, we recommend that you use the System.Xml.XmlReader class instead.

Though their object model doesn't differ in any significant way.

So, if you want to use XmlTextReader you can do something like:

public static class XmlReaderExtensions
{
    public static void EnsureRead(this XmlTextReader reader)
    {
        var isRead = reader.Read();
        if (!isRead)
            throw new InvalidOperationException("Failed to read");
    }

    public static void SkipUntil(this XmlTextReader reader, Func<XmlTextReader, Boolean> isStop)
    {
        while (!isStop(reader))
        {
            reader.EnsureRead();
        }
    }
}

...

var xml = @"<root>   <key>businessAddress</key>
    <string>Moka</string>
    <key>businessName</key>
    <string>Moka address</string>
    <key>Id</key>
    <string>39</string>
    <key>Cat</key>
    <string>216</string>
    <key>deals</key> </root>";

using (var stream = new MemoryStream(Encoding.Default.GetBytes(xml)))
using (var reader = new XmlTextReader(stream))
{
    reader.SkipUntil(cur => cur.Value == "Id");
    reader.EnsureRead(); // Skip current node
    reader.SkipUntil(cur => cur.NodeType == XmlNodeType.Text);
    Console.WriteLine("The id from XmlTextReader is {0}", reader.Value);
}

Though to be sure that it will work correctly fail fast with some xml, that doesn't correspond to the given schema, you will have to add a bit more of sanity checks, so...


You can also try LINQ-TO-XML if you are not concerned with entire xml tree being put into the memory:

using (var stream = new MemoryStream(Encoding.Default.GetBytes(xml)))
{
    var xdoc = XDocument.Load(stream);
    var id = xdoc
        .Root
        .Elements("key")
        .First(element =>
            element.Value == "Id")
        .ElementsAfterSelf("string")
        .First()
        .Value;
    Console.WriteLine("The id from XDocument is {0}", id);
}
Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53
0

Your XML looks suspiciously similar to Plist. So, sounds like you need a Plist library. Instead of reinventing the wheel, just use any of the libraries available on NuGet. They'll solve your problems with parsing the XML file.

If you insist on parsing XML manually, forget about the low-level SAX class and just use DOM. Working with XDocument is much easier. See @EugenePodskal's solution.

Athari
  • 33,702
  • 16
  • 105
  • 146