我从服务列表中收到以下字符串
<?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>
我正在尝试通过内部文本获取name的值,但无法这样做:
即
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.",
任何指针表示赞赏。
答案 0 :(得分:1)
您在这里遇到一些问题:
您正在使用旧的XmlDocument
API,该API对名称空间的处理有些不便。具体来说:
XmlNode.GetElementsByTagName(string)
是 namespace-unware 。它与“原始”合格元素名称匹配,可能包括前缀。
此方法中,Microsoft用documentation
编写注意
建议您使用
XmlNode.SelectNodes
或XmlNode.SelectSingleNode
方法而不是GetElementsByTagName
方法。
XmlNode.SelectSingleNode(string)
,支持名称空间,并且仅选择空名称空间中的元素。
来自docs:
如果XPath表达式不包含前缀,则假定名称空间URI为空名称空间。如果您的XML包含默认名称空间,则您仍必须使用
XmlNamespaceManager
并为其添加前缀和名称空间URI;否则,您将不会获得选定的节点。
这两种方法之间的不一致解释了为什么代码部分起作用的原因,因为XML文档中的所有元素都属于http://purl.org/atom/ns#
名称空间。
如果您缩进XML,很明显<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。
答案 1 :(得分:0)
给出的示例无效的XML:
<author>
由于任何这些原因,我都不希望对此进行解析。
尽管如此,NullReferenceException不能正确传达失败的原因,因此这里可能还会发生其他情况。使用调试器确定哪一行引发此异常。
假设您错过了一些XML并且它实际上是有效的,这也可能是由于未指定要选择的元素的名称空间而引起的。如果文档具有目标名称空间http://some-namespace
,则entry
不是正确的名称;您必须包括名称空间。 GetElementsByTagName
有一个overload with two arguments,其中第二个是名称空间。