Getting an XElement with a namespace via XPathSelectElements

20,748

Solution 1

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

Solution 2

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");
Share:
20,748
Charlie
Author by

Charlie

Updated on July 09, 2022

Comments

  • Charlie
    Charlie almost 2 years

    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.

  • Charlie
    Charlie over 10 years
    Yes, but how would I know if it belonged to my XPath. As you see, the same E5 node occurs at multiple paths.
  • Mike Perrenoud
    Mike Perrenoud over 10 years
    @Charlie, have a look at my edit. I leverage the Parent property to ensure it's part of a B4 element.
  • Charlie
    Charlie over 10 years
    I tried this, thank you, that works. Is this the best way of doing it? I'm just asking because my function is passed the entire XPath as a string and it doesn't have the name space as shown in your xPath variable. I can add it via string replace, but just wondering if there is any other way of doing this?
  • Charlie
    Charlie over 10 years
    this is close, but my XPath is passed as a string and I cannot dynamically check every parent up to the root node. My XML has a deep hierarchy.
  • Rubens Farias
    Rubens Farias over 10 years
    The namespace prefix isn't important, just value part; so, if you rename your prefix from sample to whatever that would be ok.
  • Charlie
    Charlie over 10 years
    may be I am missing something here, I meant that you have the prefix before each element name in the xPath variable. I was asking an alternative to this. i.e. "//sample:B2/sample:C3/sample:D4"
  • Charlie
    Charlie over 10 years
    I cannot do this, I get the XPath as a string, how do I implement that as the foreach loop you have? Plus the XPath can be n level deep. Is there a way to handle that?
  • Rubens Farias
    Rubens Farias over 10 years
    @Charlie, if your XML document have a namespace and you XPath expression don't, one of those need to be changed.