代码之家  ›  专栏  ›  技术社区  ›  Yuri Astrakhan

使用DataContractSerializer序列化没有命名空间的对象

  •  42
  • Yuri Astrakhan  · 技术社区  · 15 年前

    如何从使用DataContractSerializer序列化的对象的XML表示中删除XML命名空间?

    该对象需要序列化为非常简单的输出XML。

    • 最新和最棒-使用.NET 4 Beta 2
    • 对象将不需要反序列化。
    • XML不应具有任何xmlns:。命名空间引用
    • 需要支持exception和isubobject的任何子类型。
    • 更改原始对象将非常困难。

    对象:

     [Serializable] 
     class MyObj
     {
         string str;
         Exception ex;
         ISubObject subobj;
     } 
    

    需要序列化为:

    <xml>
      <str>...</str>
      <ex i:nil="true" />
      <subobj i:type="Abc">
         <AbcProp1>...</AbcProp1>
         <AbcProp2>...</AbcProp2>
      </subobj>
    </xml>
    

    我用了这个代码:

    private static string ObjectToXmlString(object obj)
    {
        if (obj == null) throw new ArgumentNullException("obj");
    
        var serializer =
            new DataContractSerializer(
                obj.GetType(), null, Int32.MaxValue, false, false, null,
                new AllowAllContractResolver());
    
        var sb = new StringBuilder();
        using (var xw = XmlWriter.Create(sb, new XmlWriterSettings
        {
            OmitXmlDeclaration = true,
            NamespaceHandling = NamespaceHandling.OmitDuplicates,
            Indent = true
        }))
        {
            serializer.WriteObject(xw, obj);
            xw.Flush();
    
            return sb.ToString();
        }
    }
    

    this article 我采用了DataContractResolver,因此不必声明任何子类型:

    public class AllowAllContractResolver : DataContractResolver
    {
        public override bool TryResolveType(Type dataContractType, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
        {
            if (!knownTypeResolver.TryResolveType(dataContractType, declaredType, null, out typeName, out typeNamespace))
            {
                var dictionary = new XmlDictionary();
                typeName = dictionary.Add(dataContractType.FullName);
                typeNamespace = dictionary.Add(dataContractType.Assembly.FullName);
            }
            return true;
        }
    
        public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
        {
            return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null) ?? Type.GetType(typeName + ", " + typeNamespace);
        }
    }
    
    2 回复  |  直到 13 年前
        1
  •  46
  •   marc_s    15 年前

    需要标记要序列化的类:

    [DataContract(Namespace="")]
    

    在这种情况下,数据协定序列化程序不会为序列化对象使用任何命名空间。

    马克

        2
  •  11
  •   John Saunders    13 年前

    如果您的心设置为绕过默认行为(就像我目前所做的那样),那么您将创建一个自定义的XMLwriter来绕过写入命名空间。

    using System.IO;
    using System.Xml;
    
    public class MyXmlTextWriter : XmlTextWriter
    {
      public MyXmlTextWriter(Stream stream)
        : base(stream, null)
      {
      }
    
      public override void WriteStartElement(string prefix, string localName, string ns)
      {
        base.WriteStartElement(null, localName, "");
      }
    }
    

    然后,在你的作家消费者中,如下所示:

    var xmlDoc = new XmlDocument();
    DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
    using (var ms = new MemoryStream())
    {
      using (var writer = new MyXmlTextWriter(ms))
      {
        serializer.WriteObject(writer, obj);
        writer.Flush();
        ms.Seek(0L, SeekOrigin.Begin);
        xmlDoc.Load(ms);
      }
    }
    

    并且输出中会有名称空间声明,但是不会有这样的用法:

    <TestObject xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
      <Items xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
        <string>Item1</string>
        <string>Item2</string>
      </Items>
    </TestObject>