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

Posted

技术标签:

【中文标题】使用 DataContractSerializer 序列化没有命名空间的对象【英文标题】:Serializing object with no namespaces using DataContractSerializer 【发布时间】:2010-12-23 12:29:19 【问题描述】:

如何从使用 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);
    

【问题讨论】:

【参考方案1】:

你需要标记你想要序列化的类:

[DataContract(Namespace="")]

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

马克

【讨论】:

一些子对象不受我控制,我无法更改它们。是否可以在不更改对象的情况下做到这一点? 不,抱歉 - 您无法删除现有命名空间 - 您必须能够在对象本身上指定命名空间。 不可能——所有系统类型呢? MS不能指望所有类型都可以修改,必须有其他方式:( 不,没有。删除命名空间对您来说实际上没有意义。 到目前为止,我已经实现了自己的 XmlWriter(委托给真正的 XmlWriter),它跳过了命名空间。不干净,但它有效。我怀疑 DataContractResolver 能够为我解决这个问题......将保持问题开放,看看是否有任何新的解决方案出现。【参考方案2】:

如果您一心想要绕过默认行为(就像我目前所做的那样),您可以创建一个自定义 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>

【讨论】:

XmlTextWriter 给我一个问题,通过构造函数传递设置与 XmlWriter 相比 你不想重写WriteStartAttribute 来摆脱声明吗? @CarlosP 也许,但我需要它免费命名空间以便在服务器上轻松进行 XSLT,所以这就是我的驱动力。如果我将它集成到 xml 的 WebApi 序列化中,我肯定会使用你的建议来降低加载时​​间。

以上是关于使用 DataContractSerializer 序列化没有命名空间的对象的主要内容,如果未能解决你的问题,请参考以下文章

使用 DataContractSerializer 时设置属性的初始值

使用 DataContractSerializer 和 XmlDictionaryWriter 序列化 JObject 后崩溃

在原语列表上使用 DataContractSerializer 的自定义元素名称

使用 DataContractSerializer 的接口中的显式类型

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

如何使用 DataContractSerializer 从 XMLDocument 的单个节点反序列化?