【问题标题】:Xml serialization - Hide null valuesXml 序列化 - 隐藏空值
【发布时间】: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>

【问题讨论】:

    标签: c# .net xml-serialization


    【解决方案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 所写的内容之外:如果您将某些东西序列化为属性,则可以在您的类上拥有一个名为 {PropertyName}Specified 的属性来控制它是否应该被序列化。在代码中:

      public class MyClass
      {
          [XmlAttribute]
          public int MyValue;
      
          [XmlIgnore]
          public bool MyValueSpecified;
      }
      

      【讨论】:

      • 小心,{PropertyName}Specified 属性必须是 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】:

        您可以使用模式ShouldSerialize{PropertyName} 创建一个函数,它告诉 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;
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-17
        • 2017-03-07
        相关资源
        最近更新 更多