2009-12-05 11 views
41

Wie entferne ich XML-Namespaces aus der mit DataContractSerializer serialisierten XML-Repräsentation eines Objekts?Serialisieren von Objekten ohne Namespaces mit DataContractSerializer

Dieses Objekt muss zu einer sehr einfachen XML-Ausgabe serialisiert werden.

  • Neueste & größte - mit .Net 4 Beta 2
  • Das Objekt wird nie deserialisiert werden müssen.
  • XML sollte keine xmlns haben: ... Namespace refs
  • Alle Untertypen von Exception und ISubObject müssen unterstützt werden.
  • Es wird sehr schwierig sein, das ursprüngliche Objekt zu ändern.

Objekt:

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

Need serialisiert in:

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

ich diesen Code verwendet:

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

Von this article ich eine DataContractResolver angenommen, so dass keine Subtypen erklärt werden:

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

Antwort

45

Sie müssen die Klassen, die Sie mit serialisieren mögen markieren:

[DataContract(Namespace="")] 

In diesem Fall kann der Datenvertrag Serializer keinen Namensraum für Ihre serialisierte Objekte verwenden.

Marc

+0

Einige der Unterobjekte sind nicht unter meiner Kontrolle und ich kann sie nicht ändern. Ist es möglich, ohne die Objekte zu ändern? – Yurik

+0

Nein, tut mir leid - Sie können einen vorhandenen Namespace nicht entfernen - Sie müssen den Namespace für das Objekt selbst angeben können. –

+1

Das kann nicht sein - was ist mit allen Systemtypen? MS kann nicht erwarten, dass alle Typen änderbar sind, es muss auch anders sein :( – Yurik

11

Wenn Sie Ihr Herz auf unter Umgehung des Standardverhalten festgelegt haben (wie ich zur Zeit tun), erstellen Sie eine benutzerdefinierte XmlWriter, die den Namespace-Bypässe zu schreiben.

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

Dann in Ihrem Schriftsteller Verbraucher, etwa wie folgt:

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

Und so wird der Ausgang Namespace-Deklarationen in ihm hat, aber es wird keine Verwendungen als solche:

<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 gibt mir ein Problem, Einstellung durch Konstruktor im Vergleich zu XmlWriter übergeben – Kelmen

+0

@Kelmen How So? – leat

+1

Waren Sie nicht versucht, 'WriteStartAttribute' zu ​​überschreiben, um auch die Deklarationen loszuwerden? –

Verwandte Themen