2009-12-05 18 views
41

Come si rimuovono gli spazi dei nomi XML dalla rappresentazione XML di un oggetto serializzata utilizzando DataContractSerializer?Serializzare l'oggetto senza spazi dei nomi utilizzando DataContractSerializer

Questo oggetto deve essere serializzato su un XML di output molto semplice.

  • Ultime & più grande - con .Net 4 beta 2
  • L'oggetto non sarà mai bisogno di essere deserializzato.
  • XML non dovrebbe avere alcun xmlns: ... ref di namespace
  • Devono essere supportati tutti i sottotipi di Eccezione e ISubObject.
  • Sarà molto difficile cambiare l'oggetto originale.

Oggetto:

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

Necessità di serializzare in:

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

Ho usato questo codice:

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

Da this article ho adottato una DataContractResolver in modo che nessun sottotipi hanno da dichiarare:

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

risposta

45

è necessario marcare le classi che si desidera serializzare con:

[DataContract(Namespace="")] 

In tal caso, il serializzatore contratto di dati non userà alcun namespace per gli oggetti serializzati.

Marc

+0

Alcuni degli oggetti secondari non sono sotto il mio controllo e non posso cambiarli. È possibile farlo senza cambiare gli oggetti? – Yurik

+0

No, mi dispiace - non è possibile rimuovere uno spazio dei nomi esistente - devi essere in grado di specificare lo spazio dei nomi sull'oggetto stesso. –

+1

Questo non può essere - per quanto riguarda tutti i tipi di sistema? MS non può aspettarsi che tutti i tipi siano modificabili, ci deve essere un altro modo :( – Yurik

11

Se hai il tuo cuore su bypassando il comportamento di default (come ho attualmente fare), si crea un XmlWriter personalizzato che aggira la scrittura lo spazio dei nomi.

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

Poi, nel vostro scrittore di consumo, qualcosa di simile al seguente:

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

E l'uscita avrà dichiarazioni di namespace in essa, ma non ci saranno usi come tale:

<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 mi dà un problema per passare l'impostazione tramite costruttore confronta con XmlWriter – Kelmen

+0

@Kelmen How So? – leat

+1

Non è stato tentato di sovrascrivere 'WriteStartAttribute' per eliminare anche le dichiarazioni? –

Problemi correlati