3

I'm trying to parse XML string into list, result count is always zero.

 string result = "";
            string address = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml";

            // Create the web request  
            HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;

            // Get response  
            using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
            {
                // Get the response stream  
                StreamReader reader = new StreamReader(response.GetResponseStream());

                // Read the whole contents and return as a string  
                result = reader.ReadToEnd();
            }

            XDocument doc = XDocument.Parse(result);

            var ListCurr = doc.Descendants("Cube").Select(curr => new CurrencyType() 
                    { Name = curr.Element("currency").Value, Value = float.Parse(curr.Element("rate").Value) }).ToList();

where I'm going wrong.

Manish
  • 1,246
  • 3
  • 14
  • 26

2 Answers2

5

The problem is that you're looking for elements without a namespace, whereas the XML contains this in the root element:

xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref"

That specifies the default namespace for any element. Also, currency and rate are attributes within the Cube elements - they're not subelements.

So you want something like:

XNamespace ns = "http://www.ecb.int/vocabulary/2002-08-01/eurofxref";
var currencies = doc.Descendants(ns + "Cube")
                    .Select(c => new CurrencyType {
                                     Name = (string) c.Attribute("currency"),
                                     Value = (decimal) c.Attribute("rate")
                                 })
                    .ToList(); 

Note that because I'm casting the currency attribute to string, you'll end up with a null Name property for any currencies which don't specify that attribute. If you want to skip those elements, you can do so with a Where clause either before or after the Select.

Also note that I've changed the type of Value to decimal rather than float - you shouldn't use float for currency-related values. (See this question for more details.)

Additionally, you should consider using XDocument.Load to load the XML:

XDocument doc = XDocument.Load(address);

Then there's no need to create the WebRequest etc yourself.

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Thanks for letting me know about XDocument doc = XDocument.Load(address); – Manish Sep 07 '13 at 08:37
  • @Manish: I've now edited it to use `decimal` rather than `float` - and please see my comment on the answer that you've accepted, as that won't work as-is if the current thread culture uses `,` as a decimal separator. – Jon Skeet Sep 07 '13 at 08:58
2
XDocument doc = XDocument.Parse(result);
XNamespace ns = "http://www.ecb.int/vocabulary/2002-08-01/eurofxref";

var ListCurr = doc.Descendants(ns + "Cube")
                    .Where(c=>c.Attribute("currency")!=null) //<-- Some "Cube"s do not have currency attr.
                    .Select(curr => new CurrencyType  
                    { 
                        Name = curr.Attribute("currency").Value, 
                        Value = float.Parse(curr.Attribute("rate").Value) 
                    })
                    .ToList();
I4V
  • 34,891
  • 6
  • 67
  • 79
  • 2
    It would be good to actually *explain* what the problem was rather than just posting the code. I'd also recommend using the cast rather than `float.Parse` - this code will fail in cultures which use comma as a decimal separator. – Jon Skeet Sep 07 '13 at 08:56
  • 1
    @JonSkeet You are right, but you've already explained it very well. – I4V Sep 07 '13 at 09:00