I have a dictionary class that implements IXmlSerializable with custom WriteXml and ReadXml implementation. (Full code below) When I serialize it using DataContractSerializer, the output contains namespaces for general known types such as int, long, string etc. As shown:
<?xml version="1.0" encoding="utf-16"?>
<MyDictionary>
<DictionaryItem Key="myInteger">
<Value>
<int xmlns="http://schemas.microsoft.com/2003/10/Serialization/">4</int>
</Value>
</DictionaryItem>
<DictionaryItem Key="myLong">
<Value>
<long xmlns="http://schemas.microsoft.com/2003/10/Serialization/">5</long>
</Value>
</DictionaryItem>
<DictionaryItem Key="myString">
<Value>
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">testing</string>
</Value>
</DictionaryItem>
</MyDictionary>
How can I remove it so that it looks like the below? Thanks!
<?xml version="1.0" encoding="utf-16"?>
<MyDictionary>
<DictionaryItem Key="myInteger">
<Value>
<int>4</int>
</Value>
</DictionaryItem>
<DictionaryItem Key="myLong">
<Value>
<long>5</long>
</Value>
</DictionaryItem>
<DictionaryItem Key="myString">
<Value>
<string>testing</string>
</Value>
</DictionaryItem>
</MyDictionary>
The test code I used to create the output:
private void button1_Click(object sender, EventArgs e)
{
MyDictionary myDictionary = new MyDictionary();
myDictionary.Add("myInteger", 4);
Int64 myLong = 5;
myDictionary.Add("myLong", myLong);
myDictionary.Add("myString", "testing");
string outputXml = GetXmlForObject(myDictionary);
System.IO.File.WriteAllText(@"C:\outputXml.txt", outputXml);
}
public static string GetXmlForObject(Object obj)
{
try
{
DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
StringBuilder builder = new StringBuilder();
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.NamespaceHandling = NamespaceHandling.OmitDuplicates;
xmlWriterSettings.Indent = true;
using (XmlWriter writer = XmlWriter.Create(builder, xmlWriterSettings))
{
serializer.WriteObject(writer, obj);
}
return builder.ToString();
}
catch (Exception exception)
{
return String.Empty;
}
}
Full code below:
[XmlRoot(Namespace = "")]
public class MyDictionary : Dictionary<String, Object>, IXmlSerializable, ISerializable
{
public System.Xml.Schema.XmlSchema GetSchema()
{
throw new NotImplementedException("The method is not implemented.");
}
public void ReadXml(System.Xml.XmlReader reader)
{
try
{
string key = null;
object value = null;
if (reader.IsStartElement() && !reader.IsEmptyElement)
{
reader.ReadStartElement();
while (reader.NodeType != XmlNodeType.EndElement)
{
key = reader.GetAttribute("Key");
string typeAttribute = reader.GetAttribute("Null");
reader.ReadStartElement("DictionaryItem");
if (reader.IsEmptyElement)
{
this.Add(key, null);
reader.ReadStartElement();
}
else
{
reader.ReadStartElement("Value");
value = GetValueDeserializer(reader.LocalName).ReadObject(reader.ReadSubtree());
this.Add(key, value);
reader.Skip(); // skipping in case the string is empty or null
reader.ReadEndElement(); // Reading end node for Value
}
reader.ReadEndElement(); // Reading end node for element in the list
}
reader.ReadEndElement();
}
}
catch (XmlException e)
{
throw new XmlException("ReadXml(XmlReader) reader pointing to invalid element", e);
}
}
private DataContractSerializer GetValueDeserializer(string typeStr)
{
Type valueType = GetTypeFromStratusType(typeStr);
return new DataContractSerializer(valueType);
}
public static Type GetTypeFromStratusType(string typeStr)
{
Type valueType;
switch (typeStr)
{
case "short":
valueType = typeof(Int16);
break;
case "int":
valueType = typeof(Int32);
break;
case "long":
valueType = typeof(Int64);
break;
case "string":
valueType = typeof(String);
break;
default:
valueType = typeof(String);
break;
}
return valueType;
}
public void WriteXml(System.Xml.XmlWriter writer)
{
foreach (KeyValuePair<String, Object> item in this)
{
writer.WriteStartElement("DictionaryItem");
writer.WriteAttributeString("Key", item.Key.ToString());
if (item.Value != null)
{
writer.WriteStartElement("Value");
DataContractSerializer serializer = new DataContractSerializer(item.Value.GetType());
serializer.WriteObject(writer, item.Value);
}
else
{
writer.WriteStartElement("Value");
}
writer.WriteEndElement();
writer.WriteEndElement();
}
}
}
You can create an XmlTextWriter that bypasses writing the namespace, and plug it into your serializer. By default. the serializer uses a text writer that it gets with the creation of the method XmlDictionaryWriter.CreateTextWriter(...), which does write out namespaces (which is, of course, your problem here!)
This custom serializer would not write out namespaces at all, and it should fix your problem.
public class CustomXmlTextWriter : XmlTextWriter
{
public override void WriteStartElement(string prefix, string localName, string ns)
{
base.WriteStartElement(null, localName, "");
}
}