2009-12-05 18 views
41

¿Cómo elimino los espacios de nombres XML de la representación XML de un objeto serializado utilizando DataContractSerializer?Serializar el objeto sin espacios de nombres utilizando DataContractSerializer

Ese objeto necesita ser serializado a un XML de salida muy simple.

  • reciente & mayor - el uso de .Net 4 beta 2
  • El objeto nunca tendrá que ser deserializado.
  • XML no debería tener ningún xmlns: ... espacio de nombre refs
  • Cualquier subtipo de Exception y ISubObject necesita ser admitido.
  • Será muy difícil cambiar el objeto original.

objeto:

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

Necesidad para serializar en:

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

que utiliza este código:

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

De this article Me adoptado una DataContractResolver de manera que no hay subtipos tienen ser declarado:

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

Respuesta

45

Usted necesidad de marcar las clases que desea serializar con:

[DataContract(Namespace="")] 

En ese caso, el serializador contrato de datos no utilizar ningún espacio de nombres para los objetos serializados.

Marc

+0

Algunos de los sub-objetos no están bajo mi control y no puedo cambiarlos. ¿Es posible hacerlo sin cambiar los objetos? – Yurik

+0

No, lo siento, no puede eliminar un espacio de nombres existente; debe poder especificar el espacio de nombres en el objeto mismo. –

+1

Eso no puede ser, ¿qué pasa con todos los tipos de sistema? MS no puede esperar que todos los tipos sean modificables, tiene que haber alguna otra forma :( – Yurik

11

Si usted tiene su corazón puesto en pasar por el comportamiento por defecto (como actualmente lo hago), se crea un XmlWriter a medida que pasa por encima de la escritura del espacio de nombres.

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, ""); 
    } 
} 

Luego, en su escritor del consumidor, algo así como lo siguiente:

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

Y la salida tendrá las declaraciones de espacio de nombres en ella, pero no habrá usos como por ejemplo:

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

XmlTextWriter que me da un problema para pasar la configuración a través del constructor comparar con XmlWriter – Kelmen

+0

@Kelmen ¿Cómo? – leat

+1

¿No tuvo la tentación de anular 'WriteStartAttribute' para deshacerse de las declaraciones también? –

Cuestiones relacionadas