Как десериализовать xml, игнорируя различия в типах узлов (например, XmlElement или XmlAttribute)

Как вы десериализуете xml, игнорируя разницу в типах узлов, то есть, представлен ли член как XmlElement или как XmlAttribute.

Например, у меня есть этот исходный xml

<Book>
   <Title>Introduction to c#</Title>
   <Publisher>John Smith</Publisher>
   <Year>2012</Year>
<Book>

И я хотел бы десериализовать его, используя этот класс

public class Book
{
   public string Title{ get; set; }

   [XmlAttribute()]
   public string Publisher{ get; set; }

   [XmlAttribute()]
   public string Year{ get; set; }
}

Как видите, издатель и год отмечены в классе "[XmlAttribute]", поэтому они не десериализованы.

Есть ли способ указать десериализатору игнорировать различия в том, представлен ли член как атрибут или как элемент?

Мне нужно это в универсальном преобразователе для преобразования одного типа в другой аналогичный тип

        public static Type2 ConvertType1ToType2<Type1, Type2>(Type1 type1)
        {
            using (MemoryStream objectStream = new MemoryStream())
            {
                XmlSerializer type1Serializer = new XmlSerializer(typeof(Type1));
                XmlSerializer type2Deserializer = new XmlSerializer(typeof(Type2));

                type1Serializer.Serialize(objectStream, type1);
                objectStream.Position = 0;

                return (Type2)type2Deserializer.Deserialize(objectStream);
            }
        }

person adentum    schedule 08.09.2012    source источник


Ответы (2)


Попробуйте с этим,

 string sXml = @"<Book>
                             <Title>Introduction to c#</Title>
                            <Publisher>John Smith</Publisher>
                            <Year>2012</Year>
                            </Book>";

            XmlAttributeOverrides overrides = new XmlAttributeOverrides();

            XmlAttributes PublisherAttributes = new XmlAttributes();
            XmlAttributes YearAttributes = new XmlAttributes();

            PublisherAttributes.XmlElements.Add(new XmlElementAttribute("Publisher"));
            YearAttributes.XmlElements.Add(new XmlElementAttribute("Year"));

            overrides.Add(typeof(Book), "Publisher", PublisherAttributes);
            overrides.Add(typeof(Book), "Year", YearAttributes);

           XmlSerializer ser = new XmlSerializer(typeof(Book), overrides);
           System.IO.TextReader oReader = new System.IO.StringReader(sXml);

           Book oBook = (Book) ser.Deserialize(oReader);

Это помогает?

person Jignesh Thakker    schedule 08.09.2012
comment
Спасибо за ваш ответ. Использование переопределений потребует от меня знания имен элементов, которые нужно переопределить. Знаете ли вы какие-либо общие средства для достижения этой цели? Я обновил вопрос, включив в него сценарий использования. - person adentum; 08.09.2012

Когда вы обновили свой вопрос, вам нужна общая логика для преобразования Type1 в Type2.

Попробуйте с приведенным ниже решением,

Я предположил, что для обоих классов типов (Type1 и Type2) оба имеют одинаковые свойства с одинаковыми именами.

Допустим, у нас есть два класса Book и Book1.

   public class Book
{
    public string Title { get; set; }

    [XmlAttribute()]
    public string Publisher { get; set; }

    [XmlAttribute()]
    public string Year { get; set; }
}

public class Book1
{
    public string Title { get; set; }

    [XmlAttribute()]
    public string Publisher { get; set; }

    [XmlAttribute()]
    public string Year { get; set; }
}

Функция ConvertType1ToType2:

 public static Type2 ConvertType1ToType2<Type1, Type2>(Type1 type1)
    {
        using (System.IO.MemoryStream objectStream = new System.IO.MemoryStream())
        {
             XmlRootAttribute root = new XmlRootAttribute("Book");

            //Get All MemberInfo of Type1
            Type objType1 = type1.GetType();
            System.Reflection.MemberInfo[] objType1Member = objType1.GetMembers();
            List<Type> extraTypesForType1 = new List<Type>();


            //Type1 => XmlAttributeOverrides
            XmlAttributeOverrides Type1overrides = new XmlAttributeOverrides();
            foreach (System.Reflection.MemberInfo m in objType1Member)
            {
                if (m.MemberType.Equals( System.Reflection.MemberTypes.Property))
                {
                    XmlAttributes attributes = new XmlAttributes();
                    attributes.XmlElements.Add(new XmlElementAttribute(m.Name));
                    Type1overrides.Add(typeof(Type1), m.Name, attributes);
                    extraTypesForType1.Add(m.MemberType.GetType());
                }

            }

            XmlSerializer type1Serializer = new XmlSerializer(typeof(Type1), Type1overrides, extraTypesForType1.ToArray(),root,"");

            //Type2 => XmlAttributeOverrides
            Type objType2 = type1.GetType();
            System.Reflection.MemberInfo[] objType2Member = objType1.GetMembers();

            List<Type> extraTypesForType2 = new List<Type>();

            XmlAttributeOverrides Type2overrides = new XmlAttributeOverrides();
            foreach (System.Reflection.MemberInfo m in objType2Member)
            {
                if (m.MemberType.Equals(System.Reflection.MemberTypes.Property))
                {
                    XmlAttributes attributes = new XmlAttributes();
                    attributes.XmlElements.Add(new XmlElementAttribute(m.Name));
                    Type2overrides.Add(typeof(Type2), m.Name, attributes);
                    extraTypesForType2.Add(m.MemberType.GetType());
                }

            }

            XmlSerializer type2Deserializer = new XmlSerializer(typeof(Type2), Type2overrides, extraTypesForType2.ToArray(),root,"");

            type1Serializer.Serialize(objectStream, type1);
            objectStream.Position = 0;

            Type2 t = (Type2)type2Deserializer.Deserialize(objectStream);
            return t;
        }

Теперь создайте объект класса Book и вызовите функцию ConvertType1ToType2.

Book book = new Book();
            book.Title = "Introduction to c#";
            book.Publisher = "John Smith";
            book.Year = "2012";

 Book1 book1 = ConvertType1ToType2<Book, Book1>(book);

Надеюсь, что это решение может работать.

person Jignesh Thakker    schedule 09.09.2012
comment
Спасибо за ваш подход. Мне было интересно, поскольку мы используем отражение, я думаю, мы можем пропустить часть сериализации и установить объекты напрямую? - person adentum; 11.09.2012