Deserialization using custom XmlReader
От: alexey.kostylev Новая Зеландия http://alexeykostylev.livejournal.com/
Дата: 19.09.11 22:30
Оценка:
Задача — десериализовать объект из xml без namespace. Для этого от XmlTextReader унаследовал класс, где подставляю нужный ns. Наткнулся на интересную вещь. Когда пытаюсь вытащить ns из атрибутов объекта, не работает — > System.InvalidOperationException: <Store xmlns='test.Serialization'> was not expected. Стоит заменить ns на константу все отлично работает. Причем в любом случае проверяется на равенство с константой.

environment: VS 2010, fw 3.5

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Xml;
using System.IO;

namespace VertigoDataImport
{
    static class TestSerializer
    {
        static XmlSerializer ser = new XmlSerializer(typeof(Store));
        const string nsXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"+
                "<Store xmlns=\"test.Serialization\">"+
                "   <Items Id=\"2011-09-20 09:02:37Z\" Name=\"name 1\" />"+
                "   <Items Id=\"2011-09-20 09:03:37Z\" Name=\"name 2\" />"+                
                "</Store>";
        const string bareXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                "<Store>" +
                "   <Items Id=\"2011-09-20 09:02:37Z\" Name=\"name 1\" />" +
                "   <Items Id=\"2011-09-20 09:03:37Z\" Name=\"name 2\" />" +                
                "</Store>";

        static string GetXml(Store st)
        {
            StringBuilder sb = new StringBuilder();
            
            using (var wr = XmlWriter.Create(sb))
            {
                ser.Serialize(wr, st);
                wr.Close();
            }
            var xml = sb.ToString();
            return xml;
        }

        static Store GenerateStore()
        {
            Store st = new Store
            {
                Items = new StoreItem[10]
            };

            for (int i = 0; i < 10; i++)
            {
                st.Items[i] = new StoreItem
                {
                    Id = DateTime.Now.AddMinutes(i).ToString("u"),
                    Name = string.Format("name {0}", i + 1),
                };
            }
            return st;
        }

        static Store DeserializeFromNSXml(string xml)
        {
            Store store = null;
            StringReader sr = new StringReader(nsXml);
            using (var rd = XmlReader.Create(sr))
            {
                store = (Store)ser.Deserialize(rd);
            }
            return store;
        }

        static Store DeserializeFromBareXml(string xml)
        {
            Store store = null;
            try
            {
                using (var rd = new NamespaceXmlReader(typeof(Store), new StringReader(xml), true))
                {
                    store = (Store)ser.Deserialize(rd);
                }
                Console.WriteLine("@@@ Succesfully deserialized using const ns");
            }
            catch (Exception e)
            {
                Console.WriteLine("*** Error while deserializing from bare xml using const ns.\n{0}", e.ToString());
            }            

            try
            {
                using (var rd = new NamespaceXmlReader(typeof(Store), new StringReader(xml), false))
                {
                    store = (Store)ser.Deserialize(rd);
                }
                Console.WriteLine("### Succesfully deserialized using extracted ns");
            }
            catch (Exception e)
            {
                Console.WriteLine("*** Error while deserializing from bare xml using extracted ns.\n{0}", e.ToString());
            }
            return store;
        }

        public static void Run()
        {
            Store store = DeserializeFromBareXml(bareXml);
            if (store != null)
                Console.WriteLine("deserialized. got {0} items", store.Items.Length);
            else
                Console.WriteLine("*** ERR: store is null");
            Console.Write("Press any key to exit.. ");
            Console.ReadKey();
        }
    }

    [XmlRoot(Namespace="test.Serialization")]
    [XmlType(Namespace="test.Serialization")]
    public class Store
    {
        [XmlElement()]
        public StoreItem[] Items { get; set; }
    }

    [XmlType(Namespace="test.Serialization")]
    public class StoreItem
    {
        [XmlAttribute]
        public string Id { get; set; }
        [XmlAttribute]
        public string Name { get; set; }
    }

    class NamespaceXmlReader : XmlTextReader
    {
        //const string _ns = "test.Serialization";
        static string _ns = "test.Serialization";

        string ns = "";
        public NamespaceXmlReader(Type instanceType, System.IO.TextReader reader, bool useConst)
            : base(reader)
        {
            if (useConst)
            {
                ns = _ns;
            }
            else
            {
                object[] attr_arr = instanceType.GetCustomAttributes(typeof(XmlTypeAttribute), false);
                if (attr_arr.Length == 0)
                    Console.WriteLine("*** ERR: Attribute 'XmlTypeAttribute' is not found in " + instanceType.Name);
                else
                {
                    ns = ((XmlTypeAttribute)attr_arr[0]).Namespace;
                    Console.WriteLine("> extracted ns: '{0}'", ns);
                }

                //StringBuilder sb = new StringBuilder(ns);
                //sb.Remove(ns.Length - 1, 1);
                //ns = sb.ToString() + "n";
            }
            if (string.Compare(ns, _ns) != 0)
                Console.WriteLine("*** ERR: namespace is not equal");
        }

        public override string NamespaceURI
        {
            get
            {
                if (NodeType == System.Xml.XmlNodeType.Element)
                    return ns;
                else
                    return "";
            }
        }
    }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.