Avoiding using the “http://www.w3.org/2001/XMLSche

2019-05-01 01:58发布

问题:

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?

回答1:

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 :)



回答2:

(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>