命名空间和反序列化问题

时间:2010-06-28 16:46:47

标签: c# xml-namespaces xml-deserialization

更新:您可以在此结束时运行代码以重新创建并查看我遇到的错误并希望解决它!

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

UPDATE3:问题就在这里,我需要根据现有的XmlTypeAttribute(如果它已经存在于类中的内容)来设置TypeName ....

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

我从Web服务

获取以下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>();

奇怪的是,在Deserialize方法中,RemoveAllNamespaces工作并返回没有命名空间的xml

<Systems xmlns=''> was not expected.执行时,我在catch中收到错误return (T) serializer.Deserialize(reader);

为什么这样做? xmlns是GONE !!!

可执行的代码! (只需将其放入测试项目中)

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 个答案:

答案 0 :(得分:1)

原因是问题是因为在使用此行删除命名空间时我丢失了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;
    }