Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# XML SelectNode()不返回任何内容。为什么名称空间很重要?_C#_Xml - Fatal编程技术网

C# XML SelectNode()不返回任何内容。为什么名称空间很重要?

C# XML SelectNode()不返回任何内容。为什么名称空间很重要?,c#,xml,C#,Xml,我有获取根元素节点的代码: xmlNodes = rootElement.SelectNodes("DefinitionName"); 它不会返回存在的节点。在调试器中,我可以展开rootElement以查找DefinitionName。显然,问题在于文件定义了一个名称空间(参见下面的XML)。说我必须这样做才能让节点返回: 注意:这与我的代码无关。这是MSDN中的示例: XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameT

我有获取根元素节点的代码:

xmlNodes = rootElement.SelectNodes("DefinitionName");
它不会返回存在的节点。在调试器中,我可以展开rootElement以查找DefinitionName。显然,问题在于文件定义了一个名称空间(参见下面的XML)。说我必须这样做才能让节点返回:

注意:这与我的代码无关。这是MSDN中的示例:

XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("ab", "http://www.lucernepublishing.com");
XmlNodeList nodelist = doc.SelectNodes("//ab:book", nsmgr);
我有两个问题:

  • 为什么名称空间很重要?如果我想要一个节点,并且它存在,就把它给我
  • 我的应用程序处理许多XML文件。我应该如何指定名称空间(
    nsmgr.AddNamespace()
    )?我需要先解析文件才能得到它吗
  • 我情不自禁地感到,我正在采取一种漫长的、充满焦虑的方式来做这件事

    这是XML:

        <?xml version="1.0" encoding="utf-8"?>
        <SessionStateInfo xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
        z:Id="1" z:Type="Company.Apps.MoreHere.Session.SessionStateInfo"
        z:Assembly="assembly info here"
        xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/"
        xmlns="http://schemas.datacontract.org/2004/07/MoreHere.Session">
          <CoaterNumber>25</CoaterNumber>
          <DefinitionName z:Id="2">Two Line</DefinitionName>
          <EnableManualMode>true</EnableManualMode>
    
    
    25
    双线
    真的
    
    如果您知道要查找的元素始终具有相同的本地名称,但可能具有或不具有名称空间(或可能具有不同的名称空间),则可以使用XPath技巧,如

    rootElement.SelectNodes("*[local-name() = 'DefinitionName']");
    

    这很重要,因为如果附加了名称空间,那么“DefinitionName”是不够的。想象一下,你收到了一份名单,名单上的人都叫约翰:

    • 约翰·史密斯
    • 约翰·琼斯
    • 约翰·墨菲

    你所做的相当于问“John”,而不是“John Smith”。这不是问题的确切答案,但可能是使用
    XDocument的替代解决方案

    using System;
    using System.Dynamic;
    using System.Xml.Linq;
    using Microsoft.CSharp.RuntimeBinder;
    using System.Linq;
    
    namespace ConsoleApplication8
    {
        class Program
        {
            static void Main(string[] args)
            {
                XDocument document = XDocument.Load("SessionStateInfo.xml");
                XNamespace nameSpace = document.Root.GetDefaultNamespace();
                XElement node = document.Descendants(nameSpace + "DefinitionName").FirstOrDefault();   
    
                if (node != null)
                {
                    Console.WriteLine("Cool! XDocument rocks! value: {0}", node.Value);
                }
                else
                {
                    Console.WriteLine("Spoot! Didn't find it!");
                }
            }      
        }       
    }
    

    如果指定或不指定默认名称空间,这似乎是可行的。

    节点不仅通过其本地名称(在您的示例中为DefinitionName)来标识,还通过其名称空间URI和本地名称的组合来标识。请注意,除了定义名称空间URI之外,前缀本身并不重要。所以a:x和b:x以及仅仅x通常是不同的节点:x在全局NS中,而a:x和b:x可能在不同的NSs中。例外情况是:前缀a和b可能引用相同的NS URI,或者x可能毕竟位于NS中,因为默认NS有效。然而,从你的帖子中,我不明白为什么定义名称会出现在www.lucernepublishing.com的NS中。@Dabbler我对www.lucernepublishing.com的不好。我添加了一个注释来说明这只是MSDN示例,与我的代码无关。在同一个文件中是否有两个节点具有相同的名称,每个节点具有不同的名称空间?您可以这样做:元素的本地名称相同(这可能就是您所指的“名称”),但请记住,节点总是由其名称空间URI和本地名称的组合来定义,这就是名称空间的全部要点。此示例显示,可以在不引入歧义的情况下处理书籍标题和绘画标题。如果节点位于NS中,则必须通过该NS访问它,是的。(说“如果在文件中定义了NS”有点过于简单,因为NS定义可以驻留在文档树中的任何位置,影响一些节点,但不影响其他节点。)但是,我没有看到定义名称实际上在NS中。啊,所以真正的XML有一个默认的命名空间声明(
    xmlns=“…”
    ),这使事情发生了很大的变化…+1谢谢你。这回答了我的第一个问题。但是我不能在代码中硬编码名称空间,因为我事先不知道它。有些XML文档将有一个名称空间,有些则没有。你能回答我问题中的第二点/问题吗?@BobHorn我添加了一个黑客,如果需要,你可以使用,但是名称空间的存在通常是有原因的——使用名称空间的目的是名称空间a中名为
    DefinitionName
    的元素不应与名称空间B中名为
    DefinitionName
    的元素相同。令人惊讶的是,您会有节点驻留在NSs中,稍后在处理它们时,声明您知道节点,但不知道NSs。因为如果您只关心它们的本地名称,尽管节点生活在不相交的世界中(可以这么说),这使得NSs的使用似乎是多余的。但是如果这真的是您想要的,您可以按照Siraf的建议调用local-name()来忽略NS。这是用于部署应用程序的。用户指定要在部署过程中更改的节点。应用程序本身并不知道它将处理的任何文件;它只是根据用户输入更改节点。因此,可能缺少的一点是,我还需要让用户指定一个选项名称空间?这是很有可能的。从纯XML(+名称空间)的角度来看,驻留在不同名称空间中的节点是完全不相关的,不管它们的本地名称是否恰好相等。是否只基于它们的本地名称对它们应用相同的处理超出了XML的范围,只能在业务逻辑级别上回答。
    rootElement.SelectNodes("*[local-name() = 'DefinitionName']");
    
    using System;
    using System.Dynamic;
    using System.Xml.Linq;
    using Microsoft.CSharp.RuntimeBinder;
    using System.Linq;
    
    namespace ConsoleApplication8
    {
        class Program
        {
            static void Main(string[] args)
            {
                XDocument document = XDocument.Load("SessionStateInfo.xml");
                XNamespace nameSpace = document.Root.GetDefaultNamespace();
                XElement node = document.Descendants(nameSpace + "DefinitionName").FirstOrDefault();   
    
                if (node != null)
                {
                    Console.WriteLine("Cool! XDocument rocks! value: {0}", node.Value);
                }
                else
                {
                    Console.WriteLine("Spoot! Didn't find it!");
                }
            }      
        }       
    }