Получить InnerText из XML через список - PullRequest
0 голосов
/ 04 марта 2019

Я получаю следующую строку от службы в виде списка

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

Вместо этого я получаю объект - нулевое исключение.

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

Любые указатели оценены.

Ответы [ 2 ]

0 голосов
/ 04 марта 2019

У вас есть несколько проблем:

  1. Вы используете старый XmlDocument API, который несколько неудобно обрабатывает пространства имен.В частности:

    • XmlNode.GetElementsByTagName(string) - это Пространство имен не знает .Это соответствует «необработанному» квалифицированному имени элемента, возможно, включая префикс.

      Об этом методе Microsoft пишет в документации

      Примечание

      Рекомендуется использовать метод XmlNode.SelectNodes или XmlNode.SelectSingleNode вместо метода GetElementsByTagName.

    • XmlNode.SelectSingleNode(string),наоборот, учитывает пространство имен и выбирает только элементы в пустом пространстве имен.

      Из документов :

      Если выражение XPath не содержит префикса, предполагается, что URI пространства имен является пустым пространством имен .Если ваш XML включает пространство имен по умолчанию, вы все равно должны использовать XmlNamespaceManager и добавить к нему префикс и URI пространства имен;в противном случае вы не получите выбранный узел.

    Это несоответствие между этими двумя методами объясняет, почему ваш код частично работает, поскольку все элементы в вашем XML-документе принадлежат http://purl.org/atom/ns# namespace.

  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 здесь .

Кстати, все это может быть сделано более удобно с помощью 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 здесь .

0 голосов
/ 04 марта 2019

Данный образец недопустим XML:

  • У него нет элемента документа
  • У него нет декларации XML
  • Содержитнезакрытые открывающиеся элементы <author>

Я бы не ожидал, что это будет проанализировано по любой из этих причин.

Тем не менее, исключение NullReferenceException неправильно сообщает причину сбоя, поэтому возможно, что здесь происходит что-то еще.Используйте ваш отладчик, чтобы определить, какая строка вызывает это исключение.

Если вы пропустили часть XML и он действительно действителен, это также может быть вызвано не указанием пространства имен элемента, который вы намереваетесьвыбирать.Если документ имеет целевое пространство имен http://some-namespace, entry не является правильным именем для выбора;Вы должны включить пространство имен.GetElementsByTagName имеет перегрузку с двумя аргументами , где вторым является пространство имен.

...