【问题标题】:Get InnerText from XML via List通过 List 从 XML 中获取 InnerText
【发布时间】:2019-07-25 17:49:18
【问题描述】:

我从服务中收到以下字符串作为列表返回

<?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;
}

相反,我得到的是 object is null 异常。

 "ExceptionMessage": "Object reference not set to an instance of an object.",

任何指针表示赞赏。

【问题讨论】:

  • 无法反序列化 XML,因为您缺少 &lt;/author&gt; 标记
  • xml 不正确。正如@MindSwipe 所说,它缺少最终作者标签,​​或者应该是这样的&lt;author /&gt;。并且缺少根节点,但这可能是因为您提供了一个 sn-p 而不是整个 xml。
  • 除了你的 XML 无效,考虑使用XElement; API 比XmlDocument 更友好(例如from entry in XElement.Load(response).Elements("entry") select (string) entry.Element("name"))。
  • 提示:从菜单测试 xml 在 VS 中是否良好:项目:添加新项目:XML 文件。然后将xml粘贴到视图中。错误将像错误列表中的编译器错误一样显示。缺少的标签也会用红色下划线表示。
  • 道歉 - 我已将更新添加到 xml 以关闭。还是同样的问题。 @JeroenMostert - 感谢您提出这种方法。我试过 foreach (XmlNode childrenNode2 in parentNode) { var x = (from entry in XElement.Load(response).Elements("entry") select (string)entry.Element("name")); } 但收到 "ExceptionMessage": "Invalid URI: The Uri string is too long."

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


【解决方案1】:

给出的示例不是有效的 XML:

  • 它没有文档元素
  • 它没有 XML 声明
  • 它包含未闭合的打开元素&lt;author&gt;

出于任何这些原因,我不希望它能够解析。

尽管如此,NullReferenceException 无法正确传达失败的原因,因此这里可能发生了其他事情。使用您的调试器确定是哪一行引发了此异常。

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

【讨论】:

  • 感谢您的回复@Tom W. 当我添加命名空间 XmlNodeList parentNode = xmlDoc.GetElementsByTagName("entry", "purl.org/atom/ns#"); foreach (XmlNode childrenNode2 in parentNode) { var c = childrenNode2.FirstChild.InnerText; //这可以返回第一个 ID 值 var b = childrenNode2.SelectSingleNode("name").InnerText ?? string.Empty; //对象引用未设置为对象的实例。' var d = childrenNode2.SelectSingleNode("/entry/name").InnerXml; //和上面一样的错误。
  • 命名空间警告适用于所有元素;在通过 xpath 选择它们时,无论它们在文档中的什么位置,都必须指定命名空间。与上一个问题类似,"/entry/name" 不匹配文档中的任何内容,因为 nameentry 不是文档中元素的名称,因为它们没有命名空间限定符。
【解决方案2】:

这里有几个问题:

  1. 您使用的是旧的XmlDocument API,它对命名空间的处理有些不便。具体来说:

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

      这个方法,微软写在documentation

      注意

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

    • XmlNode.SelectSingleNode(string),相反,是命名空间感知的,并且只选择空命名空间中的元素。

      来自docs

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

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

  2. 如果缩进 XML,很明显&lt;name&gt; 节点嵌套在容器&lt;author&gt; 节点中:

    <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.

【讨论】:

    猜你喜欢
    • 2011-04-18
    • 1970-01-01
    • 2011-09-07
    • 2012-07-05
    • 1970-01-01
    • 1970-01-01
    • 2018-05-08
    • 1970-01-01
    • 2012-03-18
    相关资源
    最近更新 更多