Элемент не ожидался при десериализации массива с XML-сериализацией - PullRequest
3 голосов
/ 24 марта 2010

OK. Я пытаюсь установить связь с API Pivotal Tracker, который возвращает данные только в формате XML. У меня есть следующий XML, который я пытаюсь десериализовать в мою модель предметной области.


<?xml version="1.0" encoding="UTF-8"?>
<stories type="array" count="2" total="2">
  <story>
    <id type="integer">2909137</id>
    <project_id type="integer">68153</project_id>
    <story_type>bug</story_type>
    <url>http://www.pivotaltracker.com/story/show/2909137</url>
    <current_state>unscheduled</current_state>
    <description></description>
    <name>Test #2</name>
    <requested_by>Anthony Shaw</requested_by>
    <created_at type="datetime">2010/03/23 20:05:58 EDT</created_at>
    <updated_at type="datetime">2010/03/23 20:05:58 EDT</updated_at>
  </story>
  <story>
    <id type="integer">2909135</id>
    <project_id type="integer">68153</project_id>
    <story_type>feature</story_type>
    <url>http://www.pivotaltracker.com/story/show/2909135</url>
    <estimate type="integer">-1</estimate>
    <current_state>unscheduled</current_state>
    <description></description>
    <name>Test #1</name>
    <requested_by>Anthony Shaw</requested_by>
    <created_at type="datetime">2010/03/23 20:05:53 EDT</created_at>
    <updated_at type="datetime">2010/03/23 20:05:53 EDT</updated_at>
  </story>
</stories>

Мой объект 'story' создается следующим образом:


public class story
{
     public int id { get; set; }
     public int estimate { get; set; }
     public int project_id { get; set; }

        public string story_type { get; set; }
        public string url { get; set; }
        public string current_state { get; set; }
        public string description { get; set; }
        public string name { get; set; }
        public string requested_by { get; set; }
        public string labels { get; set; }
        public string lighthouse_id { get; set; }
        public string lighthouse_url { get; set; }
        public string owned_by { get; set; }
        public string accepted_at { get; set; }
        public string created_at { get; set; }

        public attachment[] attachments { get; set; }
        public note[] notes { get; set; }
    }

Когда я выполняю свой код десериализации, я получаю следующее исключение:


Exception:
   There is an error in XML document (2, 2).

Inner Exception:
   <stories xmlns=''> was not expected.

Я могу отлично десериализовать отдельные истории, я просто не могу десериализовать этот XML в массив объектов 'истории'

И мой код десериализации (значение является строкой xml)


var byteArray = Encoding.ASCII.GetBytes(value);
var stream = new MemoryStream(byteArray);
var deserializedObject = new XmlSerializer(typeof (story[])).Deserialize(stream)

У кого-нибудь есть идеи?

Ответы [ 5 ]

9 голосов
/ 28 мая 2010

Позвольте мне предложить более краткое решение. Настройте десериализацию так, чтобы она выглядела так:

var deserializedObject = new XmlSerializer(typeof(story[]), new XmlRootAttribute("stories")).Deserialize(stream);

Указав этот второй параметр в XmlSerializer, вы можете избежать необходимости заглушать этот класс. Это позволяет сериализатору узнать, как называется корневой элемент.

Чтобы это работало, имя класса, представляющего тип элемента массива, должно точно соответствовать имени XML, например, class story {}, <story>. Вы можете обойти это (и я все равно рекомендую это как лучший метод), указав XmlType:

[XmlType("story")]
public class Story
{
...
}

Я предпочитаю делать это, поскольку это освобождает меня от застревания с именем типа XML.

4 голосов
/ 24 марта 2010

Проблема в том, что у вас нет свойства с именем "историй". Сериализатор XML не знает, что делать с элементом stories, когда видит его.

Одна вещь, которую вы можете попробовать, - это создать класс «историй»:

public class stories : List<story> {}

и используйте

var byteArray = Encoding.ASCII.GetBytes(value);
stories deserializedObject  = null;
using (var stream = new MemoryStream(byteArray))
{
    var storiesSerializer = new XmlSerializer(typeof (stories));
    deserializedObject = (stories)storiesSerializer .Deserialize(stream);
}
2 голосов
/ 24 марта 2010

Попробуйте что-то вроде

public class stories
{
    [XmlElement("story")]
    public story[] storyarray { get; set; }
}

...

var byteArray = Encoding.ASCII.GetBytes(value);
XmlSerializer serializer = new XmlSerializer(typeof(stories));
stories myStories = null;

using (var stream = new MemoryStream(byteArray))
{
    myStories = (stories)serializer.Deserialize(stream);
}

foreach (story stor in myStories.storyarray)
    Console.WriteLine(stor.story_type);

Редактировать: Обновленный пример кода для использования с использованием оператора на основе обратной связи.

1 голос
/ 24 марта 2010

XMSerializer ожидает пространство имен XML, с помощью которого можно понять ваш XML.

xmlns="http://schemas.microsoft.com"

... должен сделать. См. Пример XML внизу этой страницы.

0 голосов
/ 24 марта 2010

Я бы порекомендовал вам сгенерировать XSD из некоторого примера XML, полученного из веб-службы. Затем с помощью этого XSD вы можете сгенерировать классы, к которым прикреплены все надлежащие атрибуты сериализации.

  1. Чтобы создать схему (если вы не хотите писать свою собственную), откройте образец XML-файла в Visual Studio и выберите пункт меню XML -> Создать схему. Сохраните этот XSD.
  2. Чтобы сгенерировать классы, запустите команду XSD из командной строки VS. Если вы запустите его без параметров, он покажет вам параметры командной строки, которые вы можете использовать.
  3. Теперь вы можете создать типизированный XML сериализатор.
...