C# 如何在使用XmlSerializer时排除null属性
我正在序列化这样一个类C# 如何在使用XmlSerializer时排除null属性,c#,xml-serialization,nullable,C#,Xml Serialization,Nullable,我正在序列化这样一个类 public MyClass { public int? a { get; set; } public int? b { get; set; } public int? c { get; set; } } 所有类型都可以为null,因为我希望在序列化此类型的对象时存储最少的数据。但是,当它被序列化时,只填充了“a”,我得到以下xml <MyClass ...> <a>3</a> <b xs
public MyClass
{
public int? a { get; set; }
public int? b { get; set; }
public int? c { get; set; }
}
所有类型都可以为null,因为我希望在序列化此类型的对象时存储最少的数据。但是,当它被序列化时,只填充了“a”,我得到以下xml
<MyClass ...>
<a>3</a>
<b xsi:nil="true" />
<c xsi:nil="true" />
</MyClass>
3.
如何设置为仅获取非空属性的xml?期望的输出是
<MyClass ...>
<a>3</a>
</MyClass>
3.
我想排除这些空值,因为将有多个属性,并且这些属性存储在数据库中(是的,这不是我的调用),所以我希望将未使用的数据保持在最小值。您可以忽略具有
{field}指定的属性将通过返回true/false告诉序列化程序是否应该序列化相应的字段。我想您可以创建一个XmlWriter,用xsi:nil属性过滤掉所有元素,并将所有其他调用传递给底层的true writer。编写这样的代码的最简单方法是,精确输出非常重要:
xsd.exe
将架构转换为类xsd.exe
),并对照原始模式进行检查,以确保序列化程序正确地再现了所需的所有行为指定的
属性,但为您生成这些属性肯定比手工编写要好。:-) 将元素标记为
[XmlElement(“elementName”,IsNullable=false)]
空值将被忽略。迟做总比不做好 我找到了一种方法(可能只适用于我不知道的最新框架)。 我正在为WCF webservice合约使用DataMember属性,并将我的对象标记为:
[DataMember(EmitDefaultValue = false)]
public decimal? RentPrice { get; set; }
还有另一种解决方案:为了拯救regex,请使用
\s+
从包含XML的字符串中删除所有空属性。
我同意,这不是最优雅的解决方案,只有在您只需要序列化的情况下才有效。但这就是我今天所需要的,我不想为所有可为null的属性添加{Foo}指定的属性
public string ToXml()
{
string result;
var serializer = new XmlSerializer(this.GetType());
using (var writer = new StringWriter())
{
serializer.Serialize(writer, this);
result = writer.ToString();
}
serializer = null;
// Replace all nullable fields, other solution would be to use add PropSpecified property for all properties that are not strings
result = Regex.Replace(result, "\\s+<\\w+ xsi:nil=\"true\" \\/>", string.Empty);
return result;
}
公共字符串ToXml()
{
字符串结果;
var serializer=新的XmlSerializer(this.GetType());
使用(var writer=new StringWriter())
{
serializer.Serialize(writer,this);
结果=writer.ToString();
}
序列化程序=null;
//替换所有可为null的字段,另一种解决方案是对所有非字符串的属性使用addpropspecified属性
结果=Regex.Replace(结果“\\s+”,string.Empty);
返回结果;
}
1)扩展
public static string Serialize<T>(this T value) {
if (value == null) {
return string.Empty;
}
try {
var xmlserializer = new XmlSerializer(typeof(T));
var stringWriter = new Utf8StringWriter();
using (var writer = XmlWriter.Create(stringWriter)) {
xmlserializer.Serialize(writer, value);
return stringWriter.ToString();
}
} catch (Exception ex) {
throw new Exception("An error occurred", ex);
}
}
2) 创建XElement
XElement xml = XElement.Parse(objectToSerialization.Serialize());
3) 删除零的
xml.Descendants().Where(x => x.Value.IsNullOrEmpty() && x.Attributes().Where(y => y.Name.LocalName == "nil" && y.Value == "true").Count() > 0).Remove();
4) 保存到文件
xml.Save(xmlFilePath);
这个问题很久以前就被提出了,但即使在2017年也仍然非常相关。这里提出的答案没有一个让我不满意,因此我提出了一个简单的解决方案:
使用正则表达式是关键。因为我们对XmlSerializer的行为没有太多的控制,所以我们不要试图阻止它序列化那些可为null的值类型。相反,只需获取序列化输出,并使用正则表达式将不需要的元素替换为空字符串。使用的模式(在C#中)是:
下面是一个例子:
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;
namespace MyNamespace
{
/// <summary>
/// Provides extension methods for XML-related operations.
/// </summary>
public static class XmlSerializerExtension
{
/// <summary>
/// Serializes the specified object and returns the XML document as a string.
/// </summary>
/// <param name="obj">The object to serialize.</param>
/// <param name="namespaces">The <see cref="XmlSerializerNamespaces"/> referenced by the object.</param>
/// <returns>An XML string that represents the serialized object.</returns>
public static string Serialize(this object obj, XmlSerializerNamespaces namespaces = null)
{
var xser = new XmlSerializer(obj.GetType());
var sb = new StringBuilder();
using (var sw = new StringWriter(sb))
{
using (var xtw = new XmlTextWriter(sw))
{
if (namespaces == null)
xser.Serialize(xtw, obj);
else
xser.Serialize(xtw, obj, namespaces);
}
}
return sb.ToString().StripNullableEmptyXmlElements();
}
/// <summary>
/// Removes all empty XML elements that are marked with the nil="true" attribute.
/// </summary>
/// <param name="input">The input for which to replace the content. </param>
/// <param name="compactOutput">true to make the output more compact, if indentation was used; otherwise, false.</param>
/// <returns>A cleansed string.</returns>
public static string StripNullableEmptyXmlElements(this string input, bool compactOutput = false)
{
const RegexOptions OPTIONS =
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline;
var result = Regex.Replace(
input,
@"<\w+\s+\w+:nil=""true""(\s+xmlns:\w+=""http://www.w3.org/2001/XMLSchema-instance"")?\s*/>",
string.Empty,
OPTIONS
);
if (compactOutput)
{
var sb = new StringBuilder();
using (var sr = new StringReader(result))
{
string ln;
while ((ln = sr.ReadLine()) != null)
{
if (!string.IsNullOrWhiteSpace(ln))
{
sb.AppendLine(ln);
}
}
}
result = sb.ToString();
}
return result;
}
}
}
使用System.IO;
使用系统文本;
使用System.Text.RegularExpressions;
使用System.Xml;
使用System.Xml.Serialization;
名称空间MyNamespace
{
///
///为与XML相关的操作提供扩展方法。
///
公共静态类XmlSerialized
{
///
///序列化指定的对象并以字符串形式返回XML文档。
///
///要序列化的对象。
///对象引用的对象。
///表示序列化对象的XML字符串。
公共静态字符串序列化(此对象obj,XmlSerializerNamespaces=null)
{
var xser=新的XmlSerializer(obj.GetType());
var sb=新的StringBuilder();
使用(var sw=新的StringWriter(sb))
{
使用(var xtw=新的XmlTextWriter(sw))
{
if(名称空间==null)
序列化(xtw,obj);
其他的
序列化(xtw、obj、名称空间);
}
}
返回某人ToString().StripNullableEmptyXmlElements();
}
///
///删除所有标记为nil=“true”属性的空XML元素。
///
///要替换其内容的输入。
///如果使用缩进,则为true以使输出更紧凑;否则为false。
///干净的绳子。
公共静态字符串stripNullableEmptyXMlements(此字符串输入,bool compactOutput=false)
{
常量RegexOptions选项=
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline;
var result=Regex.Replace(
输入,
@"",
字符串。空,
选择权
);
if(压缩输出)
{
var sb=新的StringBuilder();
使用(var sr=新的StringReader(结果))
{
字符串ln;
而((ln=sr.ReadLine())!=null)
{
如果(!string.IsNullOrWhiteSpace(ln))
{
b.附肢线(ln);
}
}
xml.Save(xmlFilePath);
<\w+\s+\w+:nil="true"(\s+xmlns:\w+="http://www.w3.org/2001/XMLSchema-instance")?\s*/>
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;
namespace MyNamespace
{
/// <summary>
/// Provides extension methods for XML-related operations.
/// </summary>
public static class XmlSerializerExtension
{
/// <summary>
/// Serializes the specified object and returns the XML document as a string.
/// </summary>
/// <param name="obj">The object to serialize.</param>
/// <param name="namespaces">The <see cref="XmlSerializerNamespaces"/> referenced by the object.</param>
/// <returns>An XML string that represents the serialized object.</returns>
public static string Serialize(this object obj, XmlSerializerNamespaces namespaces = null)
{
var xser = new XmlSerializer(obj.GetType());
var sb = new StringBuilder();
using (var sw = new StringWriter(sb))
{
using (var xtw = new XmlTextWriter(sw))
{
if (namespaces == null)
xser.Serialize(xtw, obj);
else
xser.Serialize(xtw, obj, namespaces);
}
}
return sb.ToString().StripNullableEmptyXmlElements();
}
/// <summary>
/// Removes all empty XML elements that are marked with the nil="true" attribute.
/// </summary>
/// <param name="input">The input for which to replace the content. </param>
/// <param name="compactOutput">true to make the output more compact, if indentation was used; otherwise, false.</param>
/// <returns>A cleansed string.</returns>
public static string StripNullableEmptyXmlElements(this string input, bool compactOutput = false)
{
const RegexOptions OPTIONS =
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline;
var result = Regex.Replace(
input,
@"<\w+\s+\w+:nil=""true""(\s+xmlns:\w+=""http://www.w3.org/2001/XMLSchema-instance"")?\s*/>",
string.Empty,
OPTIONS
);
if (compactOutput)
{
var sb = new StringBuilder();
using (var sr = new StringReader(result))
{
string ln;
while ((ln = sr.ReadLine()) != null)
{
if (!string.IsNullOrWhiteSpace(ln))
{
sb.AppendLine(ln);
}
}
}
result = sb.ToString();
}
return result;
}
}
}
public void WriteXml(XmlWriter writer)
{
foreach (var p in GetType().GetProperties())
{
if (p.GetCustomAttributes(typeof(XmlIgnoreAttribute), false).Any())
continue;
var value = p.GetValue(this, null);
if (value != null)
{
writer.WriteStartElement(p.Name);
writer.WriteValue(value);
writer.WriteEndElement();
}
}
}