代码之家  ›  专栏  ›  技术社区  ›  CaffGeek

名称空间和反序列化问题

  •  1
  • CaffGeek  · 技术社区  · 14 年前

    更新:你可以运行代码在这结束时重新创建和看到错误,我有希望解决它!

    更新2:这不是删除xmlns=“”问题所在。。。因为您可以从初始xml字符串中删除它。问题是[XmlType(TypeName=“Systems”)]以某种方式导致它被添加。。。

    UPDATE3:问题出在这里,我需要根据现有的XmlTypeAttribute设置TypeName,如果它已经存在于类中。。。。

        xmlAttributes.XmlType = new XmlTypeAttribute
        {
            Namespace = ""
        };
    

    我从一个webservice获取以下XML作为字符串

    <Systems xmlns="">
      <System id="1">
        <sys_name>ALL</sys_name>
      </System>
      <System id="2">
        <sys_name>asdfasdf</sys_name>
      </System>
      <System id="3">
        <sys_name>fasdfasf</sys_name>
      </System>
      <System id="4">
        <sys_name>asdfasdfasdf</sys_name>
      </System>
    </Systems>
    

    然后我执行这个,把它转换成一个对象

    result = XElement.Parse(xmlResult.OuterXml).Deserialize<AwayRequestSystems>();

    <Systems xmlns=''> was not expected. 在抓什么的时候 return (T) serializer.Deserialize(reader);

    为什么要这么做?xmlns不见了!!!

    可执行代码(把它放到一个测试项目中)

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Xml;
    using System.Xml.Linq;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using System.Xml.Serialization;
    
    namespace DeserializationTest
    {
        [TestClass]
        public class UnitTest1
        {
        public TestContext TestContext { get; set; }
    
        [TestMethod]
        public void RemoveXmlnsFromSystems()
        {
            var xml = XElement.Parse(@"<Systems xmlns="""">
                          <System id=""1"">
                            <sys_name>ALL</sys_name>
                          </System>
                          <System id=""2"">
                            <sys_name>ePO</sys_name>
                          </System>
                          <System id=""3"">
                            <sys_name>iEFT</sys_name>
                          </System>
                          <System id=""4"">
                            <sys_name>Away Requests</sys_name>
                          </System>
                          <System id=""5"">
                            <sys_name>RP3</sys_name>
                          </System>
                        </Systems>");
    
            var systems = xml.Deserialize<AwayRequestSystems>();
            Assert.IsInstanceOfType(systems, typeof(AwayRequestSystems));
    
            var xmlnsFree = xml.RemoveAllNamespaces();
            var str = xmlnsFree.ToString();
    
            Debug.WriteLine(str);
    
            Assert.AreNotEqual("Error", xmlnsFree.Name.ToString(), "Serialization Error");
            Assert.IsFalse(str.Contains("xmlns"), "Xmlns still exists");
        }
        }
    
    
        [XmlType(TypeName = "Systems")]
        public class AwayRequestSystems : List<AwayRequestSystem> { }
    
        [XmlType(TypeName = "System")]
        public class AwayRequestSystem
        {
        [XmlAttribute("id")]
        public int ID { get; set; }
    
        [XmlElement("sys_name")]
        public string Name { get; set; }
        }
    
        public static class XmlSerializerFactory
        {
        private static Dictionary<Type, XmlSerializer> _serializers = new Dictionary<Type, XmlSerializer>();
    
        public static void ResetCache()
        {
            _serializers = new Dictionary<Type, XmlSerializer>();
        }
    
        public static XmlSerializer GetSerializerFor(Type typeOfT)
        {
            if (!_serializers.ContainsKey(typeOfT))
            {
            var xmlAttributes = new XmlAttributes();
            var xmlAttributeOverrides = new XmlAttributeOverrides();
    
            Debug.WriteLine(string.Format("XmlSerializerFactory.GetSerializerFor(typeof({0}));", typeOfT));
    
            xmlAttributes.XmlType = new XmlTypeAttribute
            {
                Namespace = ""
            };
    
            xmlAttributes.Xmlns = false;
    
            var types = new List<Type> { typeOfT, typeOfT.BaseType };
    
            foreach (var property in typeOfT.GetProperties())
            {
                types.Add(property.PropertyType);
            }
    
            types.RemoveAll(t => t.ToString().StartsWith("System."));
    
            foreach (var type in types)
            {
                if (xmlAttributeOverrides[type] == null)
                xmlAttributeOverrides.Add(type, xmlAttributes);
            }
    
            var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides);
            //var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides, types.ToArray(), new XmlRootAttribute(), string.Empty);
            //var newSerializer = new XmlSerializer(typeOfT, string.Empty);
    
            _serializers.Add(typeOfT, newSerializer);
            }
    
            return _serializers[typeOfT];
        }
        }
    
        public static class XElementExtensions
        {
        public static XElement RemoveAllNamespaces(this XElement source)
        {
            if (source.HasAttributes)
            source.Attributes().Where(a => a.Name.LocalName.Equals("xmlns")).Remove();
    
            return source.HasElements
                   ? new XElement(source.Name.LocalName,
                          source.Attributes()/*.Where(a => !a.Name.LocalName.Equals("xmlns"))*/,
                          source.Elements().Select(el => RemoveAllNamespaces(el))
                     )
                   : new XElement(source.Name.LocalName)
                     {
                     Value = source.Value
                     };
        }
        }
    
        public static class SerializationExtensions
        {
        public static XElement Serialize(this object source)
        {
            try
            {
            var serializer = XmlSerializerFactory.GetSerializerFor(source.GetType());
            var xdoc = new XDocument();
            using (var writer = xdoc.CreateWriter())
            {
                serializer.Serialize(writer, source, new XmlSerializerNamespaces(new[] { new XmlQualifiedName("", "") }));
            }
    
            var result = (xdoc.Document != null) ? xdoc.Document.Root : new XElement("Error", "Document Missing");
    
            return result.RemoveAllNamespaces();
            }
            catch (Exception x)
            {
            return new XElement("Error", x.ToString());
            }
        }
    
        public static T Deserialize<T>(this XElement source) where T : class
        {
            //try
            //{
            var serializer = XmlSerializerFactory.GetSerializerFor(typeof(T));
    
            var cleanxml = source.RemoveAllNamespaces();
            var reader = cleanxml.CreateReader();
    
            return (T)serializer.Deserialize(reader);
            //}
            //catch (Exception x)
            //{
            //    return null;
            //}
        }
        }
    }
    
    1 回复  |  直到 14 年前
        1
  •  1
  •   CaffGeek    14 年前

    问题是,当用这行删除名称空间时,我丢失了TypeName属性

    xmlAttributes.XmlType = new XmlTypeAttribute
    {
        Namespace = ""
    };
    

    我将工厂中的GetSerializerFor类更改为以下内容,现在可以工作了

       public static XmlSerializer GetSerializerFor(Type typeOfT)
        {
            if (!_serializers.ContainsKey(typeOfT))
            {
                Debug.WriteLine(string.Format("XmlSerializerFactory.GetSerializerFor(typeof({0}));", typeOfT));
    
                var types = new List<Type> { typeOfT, typeOfT.BaseType };
    
                foreach (var property in typeOfT.GetProperties())
                {
                    types.Add(property.PropertyType);
                }
    
                types.RemoveAll(t => t.ToString().StartsWith("System."));
    
                var xmlAttributeOverrides = new XmlAttributeOverrides();
                foreach (var type in types)
                {
                    if (xmlAttributeOverrides[type] != null) 
                        continue;
    
                    var xmlAttributes = new XmlAttributes
                                            {
                                                XmlType = new XmlTypeAttribute
                                                              {
                                                                  Namespace = "",
                                                                  TypeName = GetSerializationTypeName(type)
                                                              },
                                                Xmlns = false
                                            };
                    xmlAttributeOverrides.Add(type, xmlAttributes);
                }
    
                var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides);
                //var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides, types.ToArray(), new XmlRootAttribute(), string.Empty);
                //var newSerializer = new XmlSerializer(typeOfT, string.Empty);
    
                _serializers.Add(typeOfT, newSerializer);
            }
    
            return _serializers[typeOfT];
        }
    
        private static string GetSerializationTypeName(Type type)
        {
            var xmlTypeAttribute = TypeDescriptor.GetAttributes(type)
                .OfType<XmlTypeAttribute>().FirstOrDefault();
    
            var typeName = xmlTypeAttribute.TypeName;
            return string.IsNullOrEmpty(typeName) ? type.Name : typeName;
        }