C# &引用;名称空间';x';“未定义”;尽管先调用GetNamespacesScope
我正在尝试使用C# &引用;名称空间';x';“未定义”;尽管先调用GetNamespacesScope,c#,.net,xml,xpath,C#,.net,Xml,Xpath,我正在尝试使用xPathNavigator解析c#.NET中的有效XML文档。XML文档的开头如下所示: <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv
xPathNavigator
解析c#.NET中的有效XML文档。XML文档的开头如下所示:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns1:myResponse xmlns:ns1="ExampleNS" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<myReturn href="#2" />
我要做的是将XML文档作为字符串,将其加载到XmlDocument
对象中。然后我创建一个导航器,移动到根元素并调用GetNamespacesInScope(XmlNamespaceScope.All)
。我循环遍历这个集合,其中包含根目录上定义的xml
、soapenv
、xsd
和xsi
的名称空间,并将它们添加到名称空间管理器中。然后我创建一个xPathNavigator
并调用Evaluate
,然后获取异常
代码如下:
string response = GetXMLString();
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(response);
var xmlDocumentNavigator = xmlDocument.CreateNavigator();
xmlDocumentNavigator.MoveToFollowing(XPathNodeType.Element);
var xnm = new XmlNamespaceManager(xmlDocument.NameTable);
var namespacesInScope = xmlDocumentNavigator.GetNamespacesInScope(XmlNamespaceScope.All);
if (namespacesInScope != null)
{
foreach (var prefix in namespacesInScope.Keys)
{
xnm.AddNamespace(prefix, namespacesInScope[prefix]);
}
}
var xPathDocument = new XPathDocument(new StringReader(response));
var xPathNavigator = xPathDocument.CreateNavigator();
xPathNavigator.Evaluate("/soapenv:Envelope/soapenv:Body/ns1:myResponse/myReturn", xnm);
为什么
GetNamespacesInScope
方法不在ns1
上使用?问题是GetNamespacesInScope
只返回导航器当前节点范围内的名称空间(我猜该方法建议:)
获取所有名称空间的一种方法是遍历所有元素,获取名称空间,然后重新组装唯一的元素
字典合并代码
问题是
GetNamespacesInScope
只返回导航器当前节点范围内的名称空间(正如我猜想的方法所建议的:)
获取所有名称空间的一种方法是遍历所有元素,获取名称空间,然后重新组装唯一的元素
字典合并代码
只添加您事先知道需要执行XPath查询的名称空间怎么样 你可以直接写
xnm.AddNamespace("MyNS", "ExampleNS");
然后
xPathNavigator
.Evaluate("/soapenv:Envelope/soapenv:Body/MyNS:myResponse/myReturn", xnm);
前缀是什么并不重要,只要前缀设计的名称空间是相同的
顺便说一句,您应该对SOAP名称空间执行同样的操作,因为您的XPath查询基于前缀,并且可以生成完全相同的XML,其中具有针对相同名称空间的不同前缀
我会写一些更健壮的东西,适用于不同的SOAP生成器,比如
string response = GetXMLString();
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(response);
XmlNamespaceManager xnm = new XmlNamespaceManager(xmlDocument.NameTable);
xnm.AddNamespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
xnm.AddNamespace("ns1", "ExampleNS");
xmlDocument.CreateNavigator()
.Evaluate("/soapenv:Envelope/soapenv:Body/ns1:myResponse/myReturn", xnm);
只添加您事先知道需要执行XPath查询的名称空间怎么样 你可以直接写
xnm.AddNamespace("MyNS", "ExampleNS");
然后
xPathNavigator
.Evaluate("/soapenv:Envelope/soapenv:Body/MyNS:myResponse/myReturn", xnm);
前缀是什么并不重要,只要前缀设计的名称空间是相同的
顺便说一句,您应该对SOAP名称空间执行同样的操作,因为您的XPath查询基于前缀,并且可以生成完全相同的XML,其中具有针对相同名称空间的不同前缀
我会写一些更健壮的东西,适用于不同的SOAP生成器,比如
string response = GetXMLString();
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(response);
XmlNamespaceManager xnm = new XmlNamespaceManager(xmlDocument.NameTable);
xnm.AddNamespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
xnm.AddNamespace("ns1", "ExampleNS");
xmlDocument.CreateNavigator()
.Evaluate("/soapenv:Envelope/soapenv:Body/ns1:myResponse/myReturn", xnm);
从不喜欢名称空间在XML中声明的方式,您介绍的案例就是其中之一。无论如何,它的常见做法(可能不是标准做法)是在使用xml之前声明所有名称空间,因此您正在使用的文档可能被视为“已损坏”。从不喜欢名称空间在xml中声明的方式,其中一个是针对您介绍的案例。无论如何,它的常见做法,可能不是一个标准,xml所有名称空间都应该在使用之前声明,因此您使用的文档可能被认为是“损坏的”。这不是一个坏主意,我唯一担心的是,我可以得到的xml文档的类型是相当多样的,我不一定事先知道名称空间是什么,如果不知道请求什么,就不能编写XPath查询。如果知道目标元素的名称,还应该知道其名称空间。这不是一个坏主意,我唯一担心的是,我可以获得的xml文档的类型多种多样,而且我不一定事先知道名称空间是什么。如果不知道要请求什么,就不能编写XPath查询。如果你知道你要定位的元素名,你也应该知道它的名称空间。我实际上不知道确切的.NET实现,但对我来说,导航器的要点是你不必解析整个xml来到达一个节点。虽然这个解决方案有效,但它通过强制进行完整文档解析“扼杀”了导航器上XPath查询请求的概念。这很有效,除非同一级别的多个元素在不同的命名空间下具有相同的本地名称,但这很少发生:)我实际上不知道确切的.NET实现,但对我来说,导航器的要点是,您不必解析整个xml来访问节点。尽管此解决方案有效,但它通过强制进行完整文档解析“消除”了导航器上XPath查询请求的概念。这很有效,除非同一级别上有多个元素在不同命名空间下具有相同的本地名称,但这种情况很少发生:)