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 类型。
也可以作为函数使用。例如,如果MyValue
是int?
,则可以使用public bool MyValueSpecified => MyValue.HasValue;
。
@OfirD public bool MyValueSpecified => 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 序列化 - 隐藏空值的主要内容,如果未能解决你的问题,请参考以下文章
使用 XmlSerializer 将 XML 反序列化为类型