XPathSelectElement always returns null

后端 未结 4 645
借酒劲吻你
借酒劲吻你 2020-12-01 21:00

Why is this Xpath not working using XDocument.XPathSelectElement?

Xpath:

//Plugin/UI[1]/PluginPageCategory[1]/Page[1]/Group[1]/CommandRef[2]
<         


        
相关标签:
4条回答
  • 2020-12-01 21:03

    When namespaces are used, these must be used in the XPath query also. Your XPath query would only work against elements with no namespace (as can be verified by removing the namespace from your XML).

    Here's an example showing how you create and pass a namespace manager:

    var xml = ... XML from your post ...;
    
    var xmlReader = XmlReader.Create( new StringReader(xml) ); // Or whatever your source is, of course.
    var myXDocument = XDocument.Load( xmlReader );
    var namespaceManager = new XmlNamespaceManager( xmlReader.NameTable ); // We now have a namespace manager that knows of the namespaces used in your document.
    namespaceManager.AddNamespace( "prefix", "http://www.MyNamespace.ca/MyPath" ); // We add an explicit prefix mapping for our query.
    
    var result = myXDocument.XPathSelectElement(
        "//prefix:Plugin/prefix:UI[1]/prefix:PluginPageCategory[1]/prefix:Page[1]/prefix:Group[1]/prefix:CommandRef[2]",
        namespaceManager
    ); // We use that prefix against the elements in the query.
    
    Console.WriteLine(result); // <CommandRef ...> element is printed.
    

    Hope this helps.

    0 讨论(0)
  • 2020-12-01 21:06

    This should probably be a comment on @Cumbayah's post, but I can't seem to leave comments on anything.

    You are probably better off using something like this instead of using XmlReader to get the nametable.

    var xml = ... XML from your post ...;
    var myXDocument = XDocument.Parse(xml);
    var namespaceManager = new XmlNamespaceManager(new NameTable());
    namespaceManager.AddNamespace("prefix", "http://www.MyNamespace.ca/MyPath");
    
    var result = ...;
    
    0 讨论(0)
  • 2020-12-01 21:09

    There is a way to do it without any change to the xpath. The solution I've found is to remove the namespace when parsing the XML into the XDocument.

    Here is an exemple:

    var regex = @"(xmlns:?[^=]*=[""][^""]*[""])";
    var myXDocument = XDocument.Parse(Regex.Replace("MyXmlContent", regex, "", RegexOptions.IgnoreCase | RegexOptions.Multiline))
    

    Now that the namespace is gone, it is easyer to manipulate.

    0 讨论(0)
  • 2020-12-01 21:24

    The easiest way in your case is to use XPath axes and node test for node name and position to select the element. Your XPath selection:

    myXDocument.XPathSelectElement("//Plugin/UI[1]/PluginPageCategory[1]/Page[1]/Group[1]/CommandRef[2]", myXDocument.Root.CreateNavigator());
    

    Can be easily translate to:

    myXDocument.XPathSelectElement("/child::node()[local-name()='Plugin']/child::node()[local-name()='UI'][position()=1]/child::node()[local-name()='PluginPageCategory'][position()=1]/child::node()[local-name()='Page'][position()=1]/child::node()[local-name()='Group'][position()=1]/child::node()[local-name()='CommandRef'][position()=2]");
    

    There is no need to create and pass XmlNamespaceManager as parameter.

    0 讨论(0)
提交回复
热议问题