我从服务中收到以下字符串作为列表
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#">
<entry>
<id>1</id>
<title>Job 1</title>
<author>
<name>Jim James</name>
</author>
<modified>2018-08-10T14:50:46-04:00</modified>
</entry>
<entry>
<id>2</id>
<title>Job 2</title>
<author>
<name>John Smith</name>
</author>
<modified>2018-09-10T14:50:46-04:00</modified>
</entry>
<entry>
<id>3</id>
<title>Job 3</title>
<author>
<name>Paul Rain</name>
</author>
<modified>2018-06-10T14:50:46-04:00</modified>
</entry>
<entry>
<id>4</id>
<title>Job 4</title>
<author>
<name>Jim James</name>
</author>
<modified>2018-08-10T14:50:46-04:00</modified>
</entry>
</feed>
我试图通过内部文本获取名称的值,但无法这样做:
即
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(response); //assuming response is above xml string
XmlNodeList parentNode = xmlDoc.GetElementsByTagName("entry");
foreach (XmlNode childrenNode2 in parentNode)
{
var b = childrenNode2.SelectSingleNode("name").InnerText ?? string.Empty;
}
相反,我得到的对象是null异常。
"ExceptionMessage": "Object reference not set to an instance of an object.",
任何指针赞赏。
你有一些问题:
XmlDocument
API,它对名称空间的处理有些不方便。特别:
XmlNode.GetElementsByTagName(string)
是名称空间 - 不知道。它匹配“原始”限定元素名称,可能包括前缀。
在这种方法中,微软在documentation写道
注意
建议您使用XmlNode.SelectNodes
或XmlNode.SelectSingleNode
方法而不是GetElementsByTagName
方法。
相反,XmlNode.SelectSingleNode(string)
是名称空间感知的,只选择空名称空间中的元素。
来自docs:
如果XPath表达式不包含前缀,则假定名称空间URI是空名称空间。如果您的XML包含默认命名空间,您仍然必须使用XmlNamespaceManager
并为其添加前缀和命名空间URI;否则,您将无法获得所选节点。
这两种方法之间的这种不一致性解释了为什么您的代码部分工作,因为XML文档中的所有元素都属于http://purl.org/atom/ns#
命名空间。<name>
节点嵌套在容器<author>
节点中:
<feed version="0.3" xmlns="http://purl.org/atom/ns#">
<entry>
<id>1</id>
<title>Job 1</title>
<author>
<name>Jim James</name>
</author>
<modified>2018-08-10T14:50:46-04:00</modified>
</entry>
<!--Other entries omitted -->
</feed>
您对SelectSingleNode("name")
的调用也因为这个介入元素的存在而失败。因此,以下代码将正常工作并正确选择您的条目名称:
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(response); //assuming response is above xml string
var manager = new XmlNamespaceManager(xmlDoc.NameTable);
manager.AddNamespace("atom", @"http://purl.org/atom/ns#");
var parentNode = xmlDoc.DocumentElement.SelectNodes("./atom:entry", manager);
foreach (XmlNode childrenNode2 in parentNode)
{
var name = childrenNode2.SelectSingleNode("./atom:author/atom:name", manager)?.InnerText ?? "";
Console.WriteLine(name);
}
样品小提琴#1 here。
顺便说一句,使用LINQ to XML API可以更方便地完成这一切,完全避免使用XmlNamespaceManager
和XPath等等:
var xmlDoc = XDocument.Parse(response);
var ns = (XNamespace)@"http://purl.org/atom/ns#";
foreach (var element in xmlDoc.Root.Elements(ns + "entry"))
{
var name = element.Element(ns + "author")?.Element(ns + "name")?.Value ?? "";
Console.WriteLine(name);
}
样品小提琴#2 here。
给出的示例不是有效的XML:
<author>
由于上述任何原因,我不希望这个解析。
然而,NullReferenceException没有正确地传达失败的原因,所以这里可能还有其他东西。使用调试器确定引发此异常的行。
假设您错过了一些XML并且它实际上是有效的,这也可能是由于未指定您要选择的元素的命名空间引起的。如果文档具有目标名称空间http://some-namespace
,则entry
不是要选择的正确名称;您必须包含命名空间。 GetElementsByTagName
有一个overload with two arguments,其中第二个是命名空间。