Reading Xml With Xmlreader in C#

Reading Xml with XmlReader in C#

My experience of XmlReader is that it's very easy to accidentally read too much. I know you've said you want to read it as quickly as possible, but have you tried using a DOM model instead? I've found that LINQ to XML makes XML work much much easier.

If your document is particularly huge, you can combine XmlReader and LINQ to XML by creating an XElement from an XmlReader for each of your "outer" elements in a streaming manner: this lets you do most of the conversion work in LINQ to XML, but still only need a small portion of the document in memory at any one time. Here's some sample code (adapted slightly from this blog post):

static IEnumerable<XElement> SimpleStreamAxis(string inputUrl,
string elementName)
{
using (XmlReader reader = XmlReader.Create(inputUrl))
{
reader.MoveToContent();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name == elementName)
{
XElement el = XNode.ReadFrom(reader) as XElement;
if (el != null)
{
yield return el;
}
}
}
}
}
}

I've used this to convert the StackOverflow user data (which is enormous) into another format before - it works very well.

EDIT from radarbob, reformatted by Jon - although it's not quite clear which "read too far" problem is being referred to...

This should simplify the nesting and take care of the "a read too far" problem.

using (XmlReader reader = XmlReader.Create(inputUrl))
{
reader.ReadStartElement("theRootElement");

while (reader.Name == "TheNodeIWant")
{
XElement el = (XElement) XNode.ReadFrom(reader);
}

reader.ReadEndElement();
}

This takes care of "a read too far" problem because it implements the classic while loop pattern:

initial read;
(while "we're not at the end") {
do stuff;
read;
}

How to read xml document with XmlReader?

Specify the right namespace in the ReadToFollowing method.

using (XmlReader reader = XmlReader.Create(stream))
{
reader.ReadToFollowing("book");

reader.ReadToFollowing("author", "uri1");
var author = reader.ReadElementContentAsString();
Console.WriteLine(author);

reader.ReadToFollowing("rating", "uri1");
var rating = reader.ReadElementContentAsInt();
Console.WriteLine(rating);

// and so on
}

read repetitive blocks using XmlReader c#


reader.ReadToFollowing("OrderNumber");
plist.OrderNumber = reader.ReadElementContentAsString();
reader.ReadToFollowing("OrderQty");
plist.OrderQty = reader.ReadElementContentAsInt();

reader.ReadToFollowing("Items");

using (var innerReader = reader.ReadSubtree())
{
while (innerReader.ReadToFollowing("PN"))
{
var item = new OrderItem();
item.PN = innerReader.ReadElementContentAsString();
reader.ReadToFollowing("Color");
item.Color = innerReader.ReadElementContentAsString();

plist.OrderItems.Add(item);
}
}

reader.ReadToFollowing("foo");
var foo = reader.ReadElementContentAsString();

Where foo is tag name after the Items.

Don't forget plist.OrderItems = new List<OrderItem>();

reading xml file with XmlReader reads only the first element

Here is solution using combination of XmlReader and Xml Linq.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
while (!reader.EOF)
{
if (reader.Name != "WateringZone")
{
reader.ReadToFollowing("WateringZone");
}
if (!reader.EOF)
{
XElement wateringZone = (XElement)XElement.ReadFrom(reader);
WateringZone newZone = new WateringZone();
WateringZone.wateringZones.Add(newZone);
newZone.enabled = (Boolean)wateringZone.Element("Enabled");
newZone.name = (string)wateringZone.Element("Name");
newZone.relay = (int)wateringZone.Element("Relay");
newZone.monday = (Boolean)wateringZone.Element("Monday");
newZone.tuesday = (Boolean)wateringZone.Element("Tuesday");
newZone.wednesday = (Boolean)wateringZone.Element("Wednesday");
newZone.thursday = (Boolean)wateringZone.Element("Thursday");
newZone.friday = (Boolean)wateringZone.Element("Friday");
newZone.saturday = (Boolean)wateringZone.Element("Saturday");
newZone.sunday = (Boolean)wateringZone.Element("Sunday");
newZone.wateringTurns = wateringZone.Descendants("WateringTurn").Select(x => new WateringTurn() {
enabled = (Boolean)x.Element("Enabled"),
name = (string)x.Element("Name"),
minutes = (int)x.Element("Minutes")
}).ToList();
}
}

}
}
public class WateringZone
{
public static List<WateringZone> wateringZones = new List<WateringZone>();
public Boolean enabled { get;set;}
public string name { get;set;}
public int relay { get;set;}
public Boolean monday { get;set;}
public Boolean wednesday { get; set;}
public Boolean thursday { get; set;}
public Boolean tuesday { get; set;}
public Boolean friday { get; set;}
public Boolean saturday { get; set;}
public Boolean sunday { get; set;}
public List<WateringTurn> wateringTurns { get; set; }

}
public class WateringTurn
{
public Boolean enabled {get;set;}
public string name { get;set;}
public int minutes { get; set; }
}
}

Reading XML with XmlReader class

XML reader is going to read through each element in the XML tree, so you just need to keep going if you haven't hit the nodes you want yet by putting the reader in a loop. You're code needs to continue to loop through the XML, so it would need to look a little more like this:

using (XmlReader reader = XmlReader.Create(filepath))
{
while(reader.Read())
{
if (reader.IsStartElement())
{
switch (reader.Name)
{
case "Candidate":
string name = reader["CandidateName"];
break;

case "Vote":
string voteStr = reader["VoteString"];
break;
}
}
}
}

Of course, the more important question here is what are you trying to do with those values you are getting? Your current code doesn't actually do anything with the values except assign them to a variable that goes out of scope immediately.

Finding a value within an xml segment using XmlReader in C#

Here is one approach, using XDocument:

 string xml = @"
<DBSimulatorConfigurations>
<Configurations>
<DBSimulatorConfiguration>
<Key>Test1</Key>
<Submit>0</Submit>
<Amend>0</Amend>
<Update>0</Update>
<Delete>1</Delete>
<ResponseTimeInSeconds>100</ResponseTimeInSeconds>
</DBSimulatorConfiguration>
<DBSimulatorConfiguration>
<Key>Test2</Key>
<Submit>0</Submit>
<AutoUpdate>0</AutoUpdate>
<Amend>0</Amend>
<Update>0</Update>
<Delete>1</Delete>
<ResponseTimeInSeconds>100</ResponseTimeInSeconds>
</DBSimulatorConfiguration>
<DBSimulatorConfiguration>
</DBSimulatorConfiguration>
</Configurations>
</DBSimulatorConfigurations>";

XDocument xdoc = XDocument.Parse(xml);
//search for all nodes with <DBSimulatorConfiguration> element
var elements = xdoc.Root.Elements().Elements().Where(x => x.Name == "DBSimulatorConfiguration");
//iterate through all those eleemnt
foreach (var element in elements)
{
//now find it's child named Submit
var submitElement = element.Elements().FirstOrDefault(x => x.Name == "Submit");
//if such element is found
if (submitElement != null)
{
//here you can change Submit element, like this:
// submitElement.Value = "abc";
//or you can check for something
if (submitElement.ElementsBeforeSelf().Any(x=> x.Name == "Key" && x.Value== "Test2"))
{
//this is submitElement which is after element named Key with value Test2
submitElement.Value = "some specific value";
}
}
else
element.Add(new XElement("Submit", 999));
}

C# get XML Child node Values with XMLReader Class f

Try following :

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
var reader = XmlReader.Create(FILENAME);
reader.MoveToContent();
string ns = reader.NamespaceURI;
//if this doesn't work hard code ns
// string ns = "http://www.netapp.com/schemas/ONTAP/2007/AuditLog";

while (!reader.EOF)
{
if (reader.Name != "EventData")
{
reader.ReadToFollowing("EventData",ns);
}
if (!reader.EOF)
{
XElement eventData = (XElement)XElement.ReadFrom(reader);
foreach (XElement data in eventData.Elements("Data"))
{
Console.WriteLine("{0} : {1}", (string)data.Attribute("Name"), (string)data);
}
}
}
Console.ReadLine();

}
}
}


Related Topics



Leave a reply



Submit