简体   繁体   中英

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?

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.

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM