命名空间和反序列化问题

发布于 2024-09-07 07:40:07 字数 6685 浏览 7 评论 0原文

更新:您可以在本文末尾运行代码来重新创建并查看我遇到的错误并希望能够解决它!

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;但

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

我收到错误 ;不是预期的。return (T) serializer.Deserialize(reader); 执行时的 catch 中!

它为什么要这样做? 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;
        //}
    }
    }
}

UPDATE: You can run the code at the end of this to recreate and see the error I am having and hopefully solve it!

UPDATE2: It's not the removal of the xmlns="" that's the issue... as you can remove it from the initial xml string. The problem is with the [XmlType(TypeName = "Systems")] somehow causing it to be added...

UPDATE3: Turns out the problem is in here, I need to set the TypeName based on what is in the existing, XmlTypeAttribute if it already exists on the class....

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

I get the following XML as a string from a webservice

<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>

I then execute this, to convert it to an object

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

Strangely though, in the Deserialize method, while the RemoveAllNamespaces works and returns the xml without the namespace

I get the error <Systems xmlns=''> was not expected. in the catch when return (T) serializer.Deserialize(reader); executes!

Why is it doing this? The xmlns is GONE!!!

EXECUTABLE CODE! (Just put it in a test project)

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;
        //}
    }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

木槿暧夏七纪年 2024-09-14 07:40:07

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

The problem as it turns out was because I was losing the TypeName attribute when removing namespaces with this line

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

I changed the GetSerializerFor class in the factory to the following and it now works

   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;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文