Частично десериализовать XML в объект

У меня есть XML, который я десериализую в бизнес-объект. Для этого я использую XmlSerializer.Deserialize. Однако я хочу, чтобы один из элементов XmlElement, содержащихся в XML, оставался элементом XElement.

Это невозможно сделать напрямую (с помощью XmlElementAttribute), так как XElement не является сериализуемым. Я также попытался сериализовать этот элемент в строку (в два шага, пытаясь получить XElement), но это не удалось с ошибкой:

элемент неожиданного типа узла. Метод readelementstring можно вызывать только для элементов с простым или пустым содержимым.

Любая идея, как это можно сделать?

Вот пример xml и полученного объекта, который мне нужен:

<Person name="Joe">
  <Hobbies>
    <Hobby name="Reading" .../>
    <Hobby name="Photography" .../>
  </Hobbies>
  <HomeAddress>
    ...
  </HomeAddress>
</Person>

Объект:

 public class Person
    {
      [XmlAttribute("Name")]
      public string Name {get; set;}
      ?????
      public XElement Hobbies {get; set;}
      [XmlElement("HomeAddress")]
      public Address HomeAddress {get; set;}
    }

Попытки, которые не работают:

[XmlElement("Hobbies")]
public XElement Hobbies {get; set;}
[XmlElement("Hobbies")]
public string Hobbies {get; set;}

person joerage    schedule 14.01.2010    source источник


Ответы (2)


Чтобы избежать тяжелой работы по реализации чего-то вроде IXmlSerializable, вы можете сделать что-то вроде полускрытого сквозного свойства XmlElement; обратите внимание, однако, что это не совсем то, что вы хотите, поскольку у вас может быть только одно корневое значение XElement (а не два, как в вашем примере); для этого нужен список...

using System;
using System.ComponentModel;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
public class Person
{
    [XmlAttribute("Name")]
    public string Name { get; set; }
    [XmlIgnore]
    public XElement Hobbies { get; set; }

    [XmlElement("Hobbies")]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
    public XmlElement HobbiesSerialized
    {
        get
        {
            XElement hobbies = Hobbies;
            if(hobbies == null) return null;
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(hobbies.ToString());
            return doc.DocumentElement;
        }
        set
        {
            Hobbies = value == null ? null
                : XElement.Parse(value.OuterXml);
        }
    }
    [XmlElement("HomeAddress")]
    public Address HomeAddress { get; set; }
}

public class Address { }

static class Progmam
{
    static void Main()
    {
        var p = new Person { Hobbies = new XElement("xml", new XAttribute("hi","there")) };
        var ser = new XmlSerializer(p.GetType());
        ser.Serialize(Console.Out, p);
    }
}
person Marc Gravell    schedule 14.01.2010
comment
Очень хорошо. Я не понимаю, почему он использует внутренний узел при указании XmlElementAttribute для «Хобби». Однако у меня есть контроль над XML, поэтому я просто добавил узел-оболочку вокруг узла «Хобби», чтобы получить то, что мне нужно (вместо использования списка). Большое спасибо. - person joerage; 14.01.2010

Чтобы иметь полный контроль (и полную ответственность) за то, как создается XML, вы можете реализовать в своем классе интерфейс System.Xml.Serialization.IXmlSerializable и переопределить ReadXml и WriteXml. Мне приходилось делать это раньше с классами словарей - обязательно тщательно тестируйте, особенно с нулевыми свойствами, пустыми полями и т. д.

http://www.devx.com/dotnet/Article/29720

person sdcoder    schedule 14.01.2010