Reputation: 571
I have the following XML String (XMLText) :
<?xml version="1.0" encoding="utf-8" ?>
<RateSheet>
<rate category="children" date="2016-04-21">
<value>1.375</value>
</rate>
<rate category="music" date="2016-05-01">
<value>2.475</value>
</rate>
</RateSheet>
I need to read the following information from that XML: category, date und value
I can read category and date - but I can not read the data for value
I have this code:
using (XmlReader reader= XmlReader.Create(new StringReader(XMLText)))
{
while (reader.ReadToFollowing("rate"))
{
Rate rate = new Rate();
reader.MoveToFirstAttribute();
rate.Category = reader.Value; //text of current Node : Catagory
//*************************************************************************************
reader.MoveToNextAttribute(); //text of current Node : Date
DateTime myDate;
if ( DateTime.TryParse( reader.Value, out myDate) )
{
rate.Date = myDate;
}
//*************************************************************************************
reader.ReadToFollowing("value"); //should be 1.375 or 2.475 - but is always empty ("")
Console.WriteLine("value Element=" + reader.Value); //test: reader.Value does not the data
decimal myValue;
if (Decimal.TryParse(reader.Value, out myValue))
{
rate.Value = myValue;
}
else
{
rate.Value = -1; // this is what happens because reader.value == ""
}
//return collection with result
myRates.Add(rate);
}
}
Upvotes: 2
Views: 1252
Reputation: 34421
I like using a combination of XmlReader and Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
string XMLText = File.ReadAllText(FILENAME);
List<Rate> myRates = new List<Rate>();
using (XmlReader reader = XmlReader.Create(new StringReader(XMLText)))
{
while (!reader.EOF)
{
if (reader.Name != "rate")
{
reader.ReadToFollowing("rate");
}
if(!reader.EOF)
{
XElement xRate = (XElement)XElement.ReadFrom(reader);
Rate rate = new Rate();
rate.Category = xRate.Attribute("category").Value; //text of current Node : Catagory
DateTime myDate;
if (DateTime.TryParse(xRate.Attribute("date").Value, out myDate))
{
rate.Date = myDate;
}
Console.WriteLine("value Element=" + xRate.Element("value").Value); //test: reader.Value does not the data
decimal myValue;
if (Decimal.TryParse(xRate.Element("value").Value, out myValue))
{
rate.Value = myValue;
}
else
{
rate.Value = -1; // this is what happens because reader.value == ""
}
//return collection with result
myRates.Add(rate);
}
}
}
}
public class Rate
{
public DateTime Date { get; set; }
public decimal Value { get; set; }
public string Category { get; set; }
}
}
}
Upvotes: 0
Reputation: 2466
Here is what your code is missing. After
reader.ReadToFollowing("value");
You need to add the following line:
reader.Read();
After that it "reader.Value;" will return text inside <value>. Alternatively instead of linq or Streamreader you can use DOM and xpath:
XmlDocument doc = new XmlDocument();
doc.Load("file.xml");
List<Rate> rates = new List<Rate>();
XmlNodeList nodes = doc.SelectNodes("//rate");
foreach(XmlNode x in nodes)
{
Rate r = new Rate();
r.Category = x.Attributes["category"].Value;
r.Date = DateTime.ParseExact(x.Attributes["date"].Value,"yyyy-MM-dd", null)x.Attributes["category"].Value;
r.Value = double.Parse(x.SelectSingleNode("./value").InnerText));
rates.Add(r);
}
Upvotes: 0
Reputation: 16956
You can do simple Linq
to Xml
var myrates = doc.Descendants("rate")
.Select(r=> new Rate() {
Category = r.Attribute("category").Value,
Date = DateTime.ParseExact(r.Attribute("date").Value,"yyyy-MM-dd", null),
Value = double.Parse(r.Element("value").Value),
}).ToList();
Working Demo
Upvotes: 3