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);
我有两个问题:
nsmgr.AddNamespace()
)?我需要先解析文件才能得到它吗 <?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!");
}
}
}
}