2010-06-28 1 views
1

업데이트 :이 코드를 다시 작성하여 오류를 확인하고 해결할 수 있습니다.네임 스페이스 및 역 직렬화 문제

UPDATE2 : xmlns = ""이 문제가 아닙니다. 초기 xml 문자열에서 제거 할 수 있으므로 문제가됩니다. 문제는 [XmlType (TypeName = "Systems")]이 (가) 어떻게 든 추가되는 원인이됩니다. ...

UPDATE3 : 문제가 있음을 나타냅니다. 여기에있는 내용을 기반으로 TypeName을 설정해야합니다. 이미 클래스에있는 경우 내가 다음이 실행시킨 Web

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

에서 문자열로 다음 XML을받을

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

이, 객체로 변환 ..., XmlTypeAttribute 기존

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

은 이상하게 그래도 역 직렬화 방법에서, RemoveAllNamespaces 작동하면서 네임 스페이스 내가 캐치 return (T) serializer.Deserialize(reader);이 실행에 오류 <Systems xmlns=''> was not expected.를 얻을 수

없이 XML을 반환!

왜 이렇게 했습니까? xmlns는 없어졌습니다 !!!

실용적인 코드! 그것이 밝혀이 라인

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

와 네임 스페이스를 제거 할 때 나는 유형 이름 속성을 잃고 있기 때문에이에 GetSerializerFor 클래스를 변경했다

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

문제 (그냥 테스트 프로젝트에 넣어) 공장은 다음과 같습니다. 이제 작동합니다.

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