Xml 序列化 - 隐藏空值

Posted

技术标签:

【中文标题】Xml 序列化 - 隐藏空值【英文标题】:Xml serialization - Hide null values 【发布时间】:2011-08-14 16:20:24 【问题描述】:

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

当前 Xml 输出:

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

我想要什么:

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

【问题讨论】:

【参考方案1】:

我更喜欢创建自己的不带自动生成标签的 xml。在此我可以忽略创建具有空值的节点:

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;
    

【讨论】:

【参考方案2】:

在我的例子中,可为空的变量/元素都是字符串类型。所以,我只是简单地进行了检查,并为它们分配了 string.Empty 以防 NULL。这样我就摆脱了不必要的 nil 和 xmlns 属性(p3:nil="true" xmlns:p3="http://www.w3.org/2001/XMLSchema-instance)

// Example:

myNullableStringElement = varCarryingValue ?? string.Empty

// OR

myNullableStringElement = myNullableStringElement ?? string.Empty

【讨论】:

此解决方案非常有限,仅适用于字符串。对于其他类型,空字符串仍然是一个值。一些解析器尝试查找属性,如果找到则尝试将值转换为目标类型。对于此类解析器,缺少属性意味着 null,如果有属性,则它必须具有有效值。【参考方案3】:

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

    [XmlElement, DefaultValue("")]
    string data;

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

【讨论】:

很遗憾,这不适用于可空值类型【参考方案4】:

除了 Chris Taylor 所写的内容之外:如果您将某些东西序列化为属性,则可以在您的类上拥有一个名为 PropertyNameSpecified 的属性来控制它是否应该被序列化。在代码中:

public class MyClass

    [XmlAttribute]
    public int MyValue;

    [XmlIgnore]
    public bool MyValueSpecified;

【讨论】:

小心,PropertyNameSpecified 属性必须是 bool 类型。 也可以作为函数使用。例如,如果MyValueint?,则可以使用public bool MyValueSpecified =&gt; MyValue.HasValue; @OfirD public bool MyValueSpecified =&gt; MyValue.HasValue; 不起作用。它是吸气剂唯一的属性。同:public bool MyValueSpecified get return MyValue.HasValue; 【参考方案5】:
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;

【讨论】:

【参考方案6】:

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

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

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

public class MyClass

   [XmlElement(IsNullable = false)]
   public string Group;

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

【讨论】:

不幸的是,这仅适用于引用类型,不适用于值类型或其 Nullable 对应物。 @VincentSels 是正确的。 MSDN 说:您不能将 IsNullable 属性应用于类型为值类型的成员,因为值类型不能包含 null。此外,对于可为空的值类型,您不能将此属性设置为 false。当此类类型为 null 时,将通过将 xsi:nil 设置为 true 来对其进行序列化。【参考方案7】:

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

例如,如果你的类属性被称为MyNullableInt,你可以有

public bool ShouldSerializeMyNullableInt() 

  return MyNullableInt.HasValue;

这是一个完整的示例

public class Person

  public string Name get;set;
  public int? Age get;set;
  public bool ShouldSerializeAge()
  
    return Age.HasValue;
  

用下面的代码序列化

Person thePerson = new Person()Name="Chris";
XmlSerializer xs = new XmlSerializer(typeof(Person));
StringWriter sw = new StringWriter();
xs.Serialize(sw, thePerson);

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

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

【讨论】:

一个字:太棒了! MSDN ShouldSerialize ShouldSerialize 模式只有在属性没有用 XmlAttribute 属性标记的情况下才有效(我认为这应该有效,因为属性可能是可选的,但它不是)。 @Matze 很有趣,我没试过。我也会假设它会起作用。 @ChrisTaylor 是的;我也这么认为。棘手的是 XmlSerializer 实例的创建失败(由于反映类型时出错),直到我从可为空的 int-property 中删除 XmlAttribute。 @PierredeLESPINAY - 从 Visual Studio 2015 及更高版本开始,您可以使用:public bool ShouldSerializeAge() => Age.HasValue;

以上是关于Xml 序列化 - 隐藏空值的主要内容,如果未能解决你的问题,请参考以下文章

我怎样才能坚持protobuf网可为空值的数组

XML反序列化处理具有默认值的空标签

使用 XmlSerializer 将 XML 反序列化为类型

如何序列化数组中的空值?

使用 XmlSerializer 将空 xml 属性值反序列化为可为空的 int 属性

Kotlinx 序列化 - 自定义序列化程序以忽略空值