通过列表从XML获取InnerText

时间:2019-03-04 12:02:17

标签: c# asp.net .net xml xml-documentation

我从服务列表中收到以下字符串

<?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.",

任何指针表示赞赏。

2 个答案:

答案 0 :(得分:1)

您在这里遇到一些问题:

  1. 您正在使用旧的XmlDocument API,该API对名称空间的处理有些不便。具体来说:

    • XmlNode.GetElementsByTagName(string) namespace-unware 。它与“原始”合格元素名称匹配,可能包括前缀。

      此方法中,Mi​​crosoft用documentation

      编写
        

      注意

           

      建议您使用XmlNode.SelectNodesXmlNode.SelectSingleNode方法而不是GetElementsByTagName方法。

    • 相反,
    • XmlNode.SelectSingleNode(string)支持名称空间,并且仅选择空名称空间中的元素。

      来自docs

        

      如果XPath表达式不包含前缀,则假定名称空间URI为空名称空间。如果您的XML包含默认名称空间,则您仍必须使用XmlNamespaceManager并为其添加前缀和名称空间URI;否则,您将不会获得选定的节点。

    这两种方法之间的不一致解释了为什么代码部分起作用的原因,因为XML文档中的所有元素都属于http://purl.org/atom/ns#名称空间。

  2. 如果您缩进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:

  • 它没有文档元素
  • 它没有XML声明
  • 它包含未封闭的打开元素<author>

由于任何这些原因,我都不希望对此进行解析。

尽管如此,NullReferenceException不能正确传达失败的原因,因此这里可能还会发生其他情况。使用调试器确定哪一行引发此异常。

假设您错过了一些XML并且它实际上是有效的,这也可能是由于未指定要选择的元素的名称空间而引起的。如果文档具有目标名称空间http://some-namespace,则entry不是正确的名称;您必须包括名称空间。 GetElementsByTagName有一个overload with two arguments,其中第二个是名称空间。