Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding using the “http://www.w3.org/2001/XMLSchema-instance” namespace with .Net DataContractSerializer

I have a series of classes that I am converting to XML using .NET's DataContractSerializer in .NET 4.0. The serialisation is working fine, and I can parse the XML and recreate the .NET objects later without any difficulty.

However, most of the DataMember's are not required. [DataMember(IsRequired = false)]. This works great on de-serializing the XML, where you can then just miss the XML node out of the document, but when serializing an exisiting object into XML, the DataContractSerializer insists on writing out properties that have null values as nodes with an attribute e.g.

[DataContract(Name = "response", Namespace = "http://domain.com/name")]
public class MyResponseClass
{
    [DataMember(Name = "count", IsRequired = true, Order = 0)]
    public int Count { get; set; }

    [DataMember(Name = "info", IsRequired = false, Order = 1)]
    public InfoClass Info { get; set; }

    [DataMember(Name = "metadata", IsRequired = false, Order = 2)]
    public MetadataList Metadatas { get; set; }

}

can be serialised from

<response xmlns="http://domain.com/name">
    <count>4</count>
</response>

However, if I serialise the object, it creates:

<response xmlns="http://domain.com/name" xmlns:i="http://www.w3.org/2001/XmlSchema-instance">
    <count>4</count>
    <info i:nil="true" />
    <metadata i:nil="true" />
</response>

Is there any way to get the DataContractSerializer to not write the node instead, when it has a null value?

like image 672
Michael Shaw Avatar asked Jan 13 '13 11:01

Michael Shaw


2 Answers

Use EmitDefaultValue = false to skip default values in XML:

[DataContract(Name = "response", Namespace = "http://domain.com/name")]
public class MyResponseClass 
{
    [DataMember(Name = "count", IsRequired = true, Order = 0, EmitDefaultValue = false)]
    public int Count { get; set; }

    [DataMember(Name = "info", IsRequired = false, Order = 1, EmitDefaultValue = false)]
    public InfoClass Info { get; set; }

    [DataMember(Name = "metadata", IsRequired = false, Order = 2, EmitDefaultValue = false)]
    public MetadataList Metadatas { get; set; }
}

to remove xmlns:i="http://www.w3.org/2001/XmlSchema-instance" you have to use for example Replace() like in the following example

public void Write(string filePath, MyResponseClass myResponse)
{
    var serializer = new DataContractSerializer(typeof(MyResponseClass));

    var sb = new StringBuilder();
    using (var writer = new StringWriter(sb))
    using (var xmlWriter = XmlWriter.Create(writer))
    {
        serializer.WriteObject(xmlWriter, myResponse);
    }

    using (StreamWriter stream = new StreamWriter(filePath))
    {
        sb = sb.Replace(" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"", "");
        stream.Write(sb);
    }
}

with regards :)

like image 63
Jerzy Gebler Avatar answered Sep 28 '22 09:09

Jerzy Gebler


(I posted this answer accidentally in the wrong question, but I think it is helpful here, too, so I don't delete it for now)

[DataContract(Namespace = "")]

on top of each class makes it a lot nicer. It removes the datacontract namespaces and the ugly node prefixes. However, the standard namespace stays. That was ok for my case.

Before:

<?xml version="1.0" encoding="utf-8"?>
<root xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://schemas.datacontract.org/2004/07/MyClassname">
  <prop1>true</prop1>
  <prop2 xmlns:d2p1="http://schemas.datacontract.org/2004/07/MySubclassname">
    <d2p1:sub>true</d2p1:sub>
  </prop2>
</root>

After:

<?xml version="1.0" encoding="utf-8"?>
<root xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <prop1>true</prop1>
  <prop2>
    <sub>true</sub>
  </prop2>
</root>
like image 44
maf-soft Avatar answered Sep 28 '22 11:09

maf-soft