关于c#:Xml序列化-隐藏空值

Xml serialization - Hide null values

使用标准的.NET Xml序列化器时,有什么方法可以隐藏所有空值? 下面是我的类输出的示例。 我不想输出可为空的整数(如果将它们设置为null)。

当前Xml输出:

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<myClass>
   <myNullableInt p2:nil="true" xmlns:p2="http://www.w3.org/2001/XMLSchema-instance" />
   <myOtherInt>-1</myOtherInt>
</myClass>

我想要的是:

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<myClass>
   <myOtherInt>-1</myOtherInt>
</myClass>

您可以使用模式ShouldSerialize{PropertyName}创建一个函数,该函数告诉XmlSerializer是否应序列化该成员。

例如,如果您的类属性称为MyNullableInt,则可能有

1
2
3
4
public bool ShouldSerializeMyNullableInt()
{
  return MyNullableInt.HasValue;
}

这是一个完整的样本

1
2
3
4
5
6
7
8
9
public class Person
{
  public string Name {get;set;}
  public int? Age {get;set;}
  public bool ShouldSerializeAge()
  {
    return Age.HasValue;
  }
}

用以下代码序列化

1
2
3
4
Person thePerson = new Person(){Name="Chris"};
XmlSerializer xs = new XmlSerializer(typeof(Person));
StringWriter sw = new StringWriter();
xs.Serialize(sw, thePerson);

以下XML的结果-注意没有年龄

1
2
3
4
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Chris</Name>
</Person>


克里斯·泰勒(Chris Taylor)补充说:如果您将某些序列化为属性,则可以在您的类上具有一个名为{PropertyName}Specified的属性,以控制是否应该对其进行序列化。在代码中:

1
2
3
4
5
6
7
8
public class MyClass
{
    [XmlAttribute]
    public int MyValue;

    [XmlIgnore]
    public bool MyValueSpecified;
}


它存在一个名为XmlElementAttribute.IsNullable的属性

如果IsNullable属性设置为true,则将为已设置为null引用的类成员生成xsi:nil属性。

下面的示例显示一个应用了XmlElementAttribute的字段,并将IsNullable属性设置为false。

1
2
3
4
5
public class MyClass
{
   [XmlElement(IsNullable = false)]
   public string Group;
}

您可以查看其他XmlElementAttribute来更改序列化等中的名称。


您可以定义一些默认值,这样可以防止字段被序列化。

1
2
3
4
5
    [XmlElement, DefaultValue("")]
    string data;

    [XmlArray, DefaultValue(null)]
    List<string> data;


在我的情况下,可为空的变量/元素都是String类型。因此,我只是执行了一个检查,并为它们分配了string.Empty(如果为NULL)。这样,我摆脱了不必要的nil和xmlns属性(p3:nil =" true" xmlns:p3 =" http://www.w3.org/2001/XMLSchema-instance)

1
2
3
4
5
6
7
// Example:

myNullableStringElement = varCarryingValue ?? string.Empty

// OR

myNullableStringElement = myNullableStringElement ?? string.Empty


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private static string ToXml(Person obj)
{
  XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
  namespaces.Add(string.Empty, string.Empty);

  string retval = null;
  if (obj != null)
  {
    StringBuilder sb = new StringBuilder();
    using (XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings() { OmitXmlDeclaration = true }))
    {
      new XmlSerializer(obj.GetType()).Serialize(writer, obj,namespaces);
    }
    retval = sb.ToString();
  }
  return retval;
}


我更喜欢创建没有自动生成的标签的xml。在这种情况下,我可以忽略创建具有空值的节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static string ConvertToXML< T >(T objectToConvert)
    {
        XmlDocument doc = new XmlDocument();
        XmlNode root = doc.CreateNode(XmlNodeType.Element, objectToConvert.GetType().Name, string.Empty);
        doc.AppendChild(root);
        XmlNode childNode;

        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
        foreach (PropertyDescriptor prop in properties)
        {
            if (prop.GetValue(objectToConvert) != null)
            {
                childNode = doc.CreateNode(XmlNodeType.Element, prop.Name, string.Empty);
                childNode.InnerText = prop.GetValue(objectToConvert).ToString();
                root.AppendChild(childNode);
            }
        }            

        return doc.OuterXml;
    }