Charlie
Charlie

Reputation: 323

Getting an XElement with a namespace via XPathSelectElements

I have an XML e.g.

    <?xml version="1.0" encoding="utf-8"?>
    <A1>
       <B2>
          <C3 id="1">
             <D7>
                <E5 id="abc" />
             </D7>
             <D4 id="1">
                <E5 id="abc" />
             </D4>
             <D4 id="2">
                <E5 id="abc" />
             </D4>
          </C3>
       </B2>
    </A1>

This is may sample code:

    var xDoc = XDocument.Load("Test.xml");
    string xPath = "//B2/C3/D4";
    //or string xPath = "//B2/C3/D4[@id='1']";

    var eleList = xDoc.XPathSelectElements(xPath).ToList();
    foreach (var xElement in eleList)
    {
        Console.WriteLine(xElement);
    }

It works perfectly, but if I add a namespace to the root node A1, this code doesn't work. Upon searching for solutions, I found this one, but it uses the Descendants() method to query the XML. From my understanding, this solution would fail if I was searching for <E5> because the same tag exists for <D7>, <D4 id="1"> and <D4 id="2">

My requirement is to search if a node exists at a particular XPath. If there is a way of doing this using Descendants, I'd be delighted to use it. If not, please guide me on how to search using the name space.

My apologies in case this is a duplicate.

Upvotes: 12

Views: 23516

Answers (3)

Rubens Farias
Rubens Farias

Reputation: 57946

To keep using XPath, you can use something link this:

    var xDoc = XDocument.Parse(@"<?xml version='1.0' encoding='utf-8'?>
        <A1 xmlns='urn:sample'>
            <B2>
                <C3 id='1'>
                    <D7><E5 id='abc' /></D7>
                    <D4 id='1'><E5 id='abc' /></D4>
                    <D4 id='2'><E5 id='abc' /></D4>
                </C3>
            </B2>
        </A1>");

    // Notice this
    XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
    nsmgr.AddNamespace("sample", "urn:sample");

    string xPath = "//sample:B2/sample:C3/sample:D4";

    var eleList = xDoc.XPathSelectElements(xPath, nsmgr).ToList();
    foreach (var xElement in eleList)
    {
        Console.WriteLine(xElement);
    }

Upvotes: 17

Sid M
Sid M

Reputation: 4354

Try this

var xDoc = XDocument.Parse("<A1><B2><C3 id=\"1\"><D7><E5 id=\"abc\" /></D7><D4 id=\"1\"><E5 id=\"abc\" /></D4><D4 id=\"2\"><E5 id=\"abc\" /></D4></C3></B2></A1>");
        foreach (XElement item in xDoc.Element("A1").Elements("B2").Elements("C3").Elements("D4"))
        {
            Console.WriteLine(item.Element("E5").Value);//to get the value of E5
            Console.WriteLine(item.Element("E5").Attribute("id").Value);//to get the value of attribute
        }

Upvotes: 0

Mike Perrenoud
Mike Perrenoud

Reputation: 67898

but it uses the Descendants() method to query the XML. From my understanding, this solution would fail if I was searching for because the same tag exists for , and

I'm pretty sure you're not quite understanding how that works. From the MSDN documentation:

Returns a filtered collection of the descendant elements for this document or element, in document order. Only elements that have a matching XName are included in the collection.

So in your case, just do this:

xDoc.RootNode
    .Descendants("E5")
    .Where(n => n.Parent.Name.LocalName == "B4");

Upvotes: 1

Related Questions