Frode Lillerud
Frode Lillerud

Reputation: 7394

Parse XML with duplicate elementnames in C#?

I'm trying to parse the following XML structure in C#. I want to create an List> with the currencies.

<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01"   xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
<gesmes:subject>Reference rates</gesmes:subject>
<gesmes:Sender>
<gesmes:name>European Central Bank</gesmes:name>
</gesmes:Sender>
<Cube>
  <Cube time="2013-09-27">
    <Cube currency="USD" rate="1.3537"/>
    <Cube currency="JPY" rate="133.28"/>
    <Cube currency="BGN" rate="1.9558"/>
    <Cube currency="CZK" rate="25.690"/>
    <Cube currency="DKK" rate="7.4573"/>
    (....)

I've tried using XDocument.Descendants, but it's not returning anything. I'm guessing it has to do with the fact that the Cube-element is used in several levels.

XDocument xdoc = XDocument.Parse(xml);
var currencies = from cube in xdoc.Descendants("Cube")
                    select new
                        {
                            Currency = cube.Attribute("currency").Value,
                            Rate = cube.Attribute("rate").Value
                        };

foreach (var currency in currencies)
    this.Add(new KeyValuePair<string, double>(currency.Currency, Convert.ToDouble(currency.Rate)));

How can I parse the XML structure to get the currencies?

Upvotes: 2

Views: 303

Answers (3)

L.B
L.B

Reputation: 116188

You have two problems with your code

  • Every Cube doesn't have currency and rate attribute
  • You ignore the Xml namespace

Since it seems you want to create a dictionary according to your code:

XNamespace ns = "http://www.ecb.int/vocabulary/2002-08-01/eurofxref";
var xDoc = XDocument.Load(fname);

var dict = xDoc.Descendants(ns + "Cube")
               .Where(cube => cube.Attributes().Any(a => a.Name == "currency"))
               .ToDictionary(cube => cube.Attribute("currency").Value,
                             cube => (decimal)cube.Attribute("rate"));

PS: You don't have to parse the rate explicitly. It can be done while reading the xml by casting

Upvotes: 3

rene
rene

Reputation: 42494

You have to add a namespace (the Cube elements are not in the default empty namespace) and you have to check if the Cube element has indeed the currency attribute.

This is the closest solution to your curent code that will work:

XDocument xdoc = XDocument.Parse(xml);
XNamespace nsSys = "http://www.ecb.int/vocabulary/2002-08-01/eurofxref";

var currencies = from cube in xdoc.Descendants(nsSys+ "Cube")
                 where cube.Attribute("currency") !=null
                 select new
                 {
                      Currency = cube.Attribute("currency").Value,
                      Rate = cube.Attribute("rate").Value
                 };

Used this Answer as reference

Upvotes: 1

Sunil
Sunil

Reputation: 624

Try xdoc.XPathSelectElements("//Cube/Cube/Cube[@name='currency']")

Upvotes: 1

Related Questions