开发者

XPathSelectElement always returns null

开发者 https://www.devze.com 2023-03-01 12:58 出处:网络
Why is this Xpath not working using XDocument.XPathSelectElement? Xpath: //Plugin/UI[1]/PluginPageCategory[1]/开发者_如何学JAVAPage[1]/Group[1]/CommandRef[2]

Why is this Xpath not working using XDocument.XPathSelectElement?

Xpath:

//Plugin/UI[1]/PluginPageCategory[1]/开发者_如何学JAVAPage[1]/Group[1]/CommandRef[2]

XML

<Plugin xmlns="http://www.MyNamespace.ca/MyPath">
  <UI>
    <PluginPageCategory>
      <Page>
        <Group>
          <CommandRef>
            <Images>
            </Images>
          </CommandRef>
          <CommandRef>
            <Images>
            </Images>
          </CommandRef>
        </Group>
      </Page>
    </PluginPageCategory>
  </UI>
</Plugin>

C# Code:

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


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.


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 = ...;


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.


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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号