views:

191

answers:

3

So I'm trying to parse an xml file:

 <?xml version="1.0" encoding="utf-8" ?>
<Root>    
  <att1 name="bob" age="unspecified" xmlns="http://foo.co.uk/nan"&gt;    
  </att1>    
</Root>

Using the following code:

XElement xDoc= XElement.Load(filename);
var query = from c in xDoc.Descendants("att1").Attributes() select c;
foreach (XAttribute a in query)
{
    Console.WriteLine("{0}, {1}",a.Name,a.Value);
}

Nothing is written to the console unless I delete xmlns="http://foo.co.uk/nan" from the xml file, after which, I get a list of attribute names and values as one would expect, and as I need!

Edit: Formatting.

+2  A: 

You have to use the same namespace in your code:

XElement xDoc= XElement.Load(filename);
XNamespace ns = "http://foo.co.uk/nan";
var query = from c in xDoc.Descendants(ns + "att1").Attributes() select c;
foreach (XAttribute a in query)
{
    Console.WriteLine("{0}, {1}",a.Name,a.Value);
}

Attributes don't pick up the default (xmlns=....) namespace, so you don't need to qualify them. The namespace tag (xmln:tags=....)is purely local to the document or API use, the names are really namespace + local name always so you have to always specify the namespace.

Richard
This did the trick perfectly, thanks. Since the namespace is likely to change between xml files, I guess you have to load the file as a string, then look for the namespace and declare it in the code?
zotty
@zotty No string parsing is needed if you query against the LocalName as shown in my answer.
Lachlan Roche
@zotty: If namespaces vary your code will be more verbose, and it is really missing the point of namespaces (the name of a node is namespace+local name), but this is sometimes necessary.
Richard
A: 

You need to specify the namespace in the Descendants call, like this:

XNamespace ns = "http://foo.co.uk/nan";
foreach (XAttribute a in xDoc.Descendants(ns + "att1"))
{
    Console.WriteLine("{0}, {1}",a.Name,a.Value);
}
SLaks
A: 

Your call to Descendants is querying for an element named "att1" in no namespace.

If you called Descendants("{http://foo.co.uk/nan}att1") you would select the namespaced element but not the non-namespaced element.

You could select elements named "att1" in any or no namespace like this:

var query = from c in xDoc.Descendants() where c.Name.LocalName == "att1" select c.Attributes;
Lachlan Roche