Dan Smith
Dan Smith

Reputation: 290

Use LINQ XML with a namespace

I am trying to find nodes in an XML document like this:

<?xml version="1.0"?>
<TrainingCenterDatabase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2">
  <Activities>
    <Activity Sport="CyclingTransport">
      <Id>2014-07-08T15:28:14Z</Id>
    </Activity>
  </Activities>
</TrainingCenterDatabase>

I aim to extract the node value 'Id' with code like this:

XDocument doc = XDocument.Load(filePath);
List<string> urlList = doc.Root.Descendants("Id")
                          .Select(x => (string)x)
                          .ToList();
Console.WriteLine(urlList.Count);

However the count is 0, where I expect 1.

After some debugging and editing the XML I noticed that if I change the TrainingCenterDatabase node and remove the attributes to this:

<TrainingCenterDatabase>

Then the result is a count of 1 as expected.

So my question is how do I take into account the namespaces so that I can get the value when the TrainingCenterDatabase node has these attributes?

Upvotes: 4

Views: 691

Answers (2)

Thirisangu Ramanathan
Thirisangu Ramanathan

Reputation: 614

It Works...

        XDocument doc = XDocument.Load(filePath);
        XNamespace ns = "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2";
        var root = doc.Descendants(ns + "Id").Select(x => x.Value).ToList();
        Console.WriteLine(root.Count);

Upvotes: 0

Matthew Haugen
Matthew Haugen

Reputation: 13286

Namespaces in XML can be tricky. I've run into this problem myself a number of times. In all likelihood, the following will fix your problem:

XDocument doc = XDocument.Load(filePath);
List<string> urlList = doc.Root.Descendants(doc.Root.Name.Namespace.GetName("Id"))
                          .Select(x => (string)x)
                          .ToList();
Console.WriteLine(urlList.Count);

Basically, this just assumes the underlying element to have the same namespace as your root element. That's true in this case, but of course it doesn't have to be.

The right way, probably, is to do it explicitly. Now, granted, that kind of depends on how you're using this and your datasource, so make the decision for yourself, but that would require doing something more like this:

XDocument doc = XDocument.Load(filePath);
List<string> urlList = doc.Root.Descendants(System.Xml.Linq.XName.Get("Id", "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"))
                          .Select(x => (string)x)
                          .ToList();
Console.WriteLine(urlList.Count);

The cause for your problem was that the default behavior for XElement, when not given an explicit namespace, is to assume no namespace. However, the default behavior for the XML spec is to assume the parent's namespace. In your case, those two were different, so it wasn't able to find the descendant.

Upvotes: 5

Related Questions