How do I remove XML namespaces from an object's XML representation serialized using DataContractSerializer?
That object needs to be serialized to a very simple output XML.
Object:
[Serializable] class MyObj { string str; Exception ex; ISubObject subobj; }
Need to serialize into:
<xml> <str>...</str> <ex i:nil="true" /> <subobj i:type="Abc"> <AbcProp1>...</AbcProp1> <AbcProp2>...</AbcProp2> </subobj> </xml>
I used this code:
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(); } }
From this article I adopted a DataContractResolver so that no subtypes have to be declared:
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); } }
Yes, you can tell the XmlSerializer to ignore namespaces during de-serialization.
To create a type that conforms to the contract, first apply the DataContractAttribute to the class. Then apply the DataMemberAttribute to every field or property that you want to serialize. You can apply the DataMemberAttribute to both private and public members. The final format of the XML need not be text.
DataContractSerializer as the Default By default WCF uses the DataContractSerializer class to serialize data types.
You need to mark the classes you want to serialize with:
[DataContract(Namespace="")]
In that case, the data contract serializer will not use any namespace for your serialized objects.
Marc
If you have your heart set on bypassing the default behavior (as I currently do), you create a custom XmlWriter that bypasses writing the namespace.
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, ""); } }
Then in your writer consumer, something like the following:
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); } }
And the output will have namespace declarations in it, but there will be no usages as such:
<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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With