XPathSelectElement sempre retorna nulo

Por que este Xpath não está funcionando usando o XDocument.XPathSelectElement?

Xpath:

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

XML

                   

Código C #:

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

Quando namespaces são usados, eles devem ser usados ​​na consulta XPath também. Sua consulta XPath só funcionaria em elementos sem namespace (como pode ser verificado removendo o namespace do seu XML).

Aqui está um exemplo mostrando como você cria e passa um gerenciador de espaço para nome:

 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); //  element is printed. 

Espero que isto ajude.

Isso provavelmente deve ser um comentário no post do @Cumbayah, mas não consigo deixar comentários sobre nada.

Provavelmente, é melhor usar algo assim em vez de usar o XmlReader para obter o nome.

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

A maneira mais fácil no seu caso é usar eixos XPath e teste de nó para nome e posição do nó para selecionar o elemento. Sua seleção XPath:

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

Pode ser facilmente traduzido para:

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

Não há necessidade de criar e passar XmlNamespaceManager como parâmetro.

Existe uma maneira de fazer isso sem qualquer alteração no xpath. A solução que encontrei é remover o namespace ao analisar o XML no XDocument.

Aqui está um exemplo:

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

Agora que o espaço de nomes desapareceu, é mais fácil manipular.