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

Yur*_*rik 42 .net namespaces xml-serialization datacontractserializer

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

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

  • 最新和最好 - 使用.Net 4 beta 2
  • 该对象永远不需要反序列化.
  • XML不应该有任何xmlns:...命名空间引用
  • 需要支持Exception和ISubObject的任何子类型.
  • 改变原始对象将非常困难.

宾语:

 [Serializable] 
 class MyObj
 {
     string str;
     Exception ex;
     ISubObject subobj;
 } 
Run Code Online (Sandbox Code Playgroud)

需要序列化为:

<xml>
  <str>...</str>
  <ex i:nil="true" />
  <subobj i:type="Abc">
     <AbcProp1>...</AbcProp1>
     <AbcProp2>...</AbcProp2>
  </subobj>
</xml>
Run Code Online (Sandbox Code Playgroud)

我用过这段代码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这篇文章中我采用了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);
    }
}
Run Code Online (Sandbox Code Playgroud)

mar*_*c_s 46

您需要标记要序列化的类:

[DataContract(Namespace="")]
Run Code Online (Sandbox Code Playgroud)

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

  • 那不可能 - 所有的系统类型呢?MS不能指望所有类型都可以修改,还有其他方式:( (2认同)
  • 不,没有.删除命名空间对你来说实际上没有意义. (2认同)
  • 到目前为止,我已经实现了我自己的XmlWriter(委托给真正的一个)来跳过命名空间.不干净,但它的工作原理.我怀疑DataContractResolver能够为我解决这个问题......将保持问题的开放,看看是否有新的解决方案出现. (2认同)

lea*_*eat 11

如果您的心脏设置绕过默认行为(就像我目前所做的那样),您可以创建一个绕过编写命名空间的自定义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, "");
  }
}
Run Code Online (Sandbox Code Playgroud)

然后在您的编写者消费者中,类似于以下内容:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

输出中将包含名称空间声明,但不会有这样的用法:

<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>
Run Code Online (Sandbox Code Playgroud)