如何使用的XmlSerializer时要排除空属性(How to exclude null prop

2019-08-17 11:18发布

我序列化这样一个类

public MyClass
{
    public int? a { get; set; }
    public int? b { get; set; }
    public int? c { get; set; }
}

因为我想序列化这个类型的对象时存储的最小数据中的所有类型都是空。 然而,当它被序列化,只有“一”人口,我得到下面的XML

<MyClass ...>
    <a>3</a>
    <b xsi:nil="true" />
    <c xsi:nil="true" />
</MyClass>

如何设置这个最多只能得到XML对于非空的属性? 所期望的输出将是

<MyClass ...>
    <a>3</a>
</MyClass>

我要排除这些空值,因为将有几个属性,这是越来越存储在数据库中(是的,那不是我的电话),所以我想保留未使用的数据很少。

Answer 1:

我想你可以创建一个过滤掉与XSI的所有元素的的XmlWriter:无属性,并通过了所有其他调用底层的真正的作家。



Answer 2:

你忽略了与特定元素规范

public MyClass
{
    public int? a { get; set; }

    [System.Xml.Serialization.XmlIgnore]
    public bool aSpecified { get { return this.a != null; } }

    public int? b { get; set; }
    [System.Xml.Serialization.XmlIgnore]
    public bool bSpecified { get { return this.b != null; } }

    public int? c { get; set; }
    [System.Xml.Serialization.XmlIgnore]
    public bool cSpecified { get { return this.c != null; } }
}

该{}字段指定的属性会告诉串行是否应该通过返回真/假序列的相应字段与否。



Answer 3:

迟到总比不到好...

我找到了一种方法(也许仅适用于我不知道最新的框架)来做到这一点。 我使用的DataMember属性为WCF web服务合同,标志着我我的对象是这样的:

[DataMember(EmitDefaultValue = false)]
public decimal? RentPrice { get; set; }


Answer 4:

你读过这样:序列化可空INT ?



Answer 5:

又一解决方案:正则表达式来救援,使用\s+<\w+ xsi:nil="true" \/>以从包含XML的字符串中删除所有空属性。 我同意,没有最完美的解决方案,只有当你只需要序列化的作品。 但是,这是我所需要的今天,我不想要添加{Foo}Specified属性的所有可为空的属性。

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;
}


Answer 6:

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);
        }
    }

1a)的Utf8StringWriter

public class Utf8StringWriter : StringWriter {
    public override Encoding Encoding { get { return Encoding.UTF8; } }
}

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);


Answer 7:

这个问题是问了相当长一段时间以前,但仍然是,即使在2017年没有在这里所提出的答案并不令人满意我,所以这是我想出了一个简单的解决方案非常重要:

使用正则表达式是关键。 因为我们有超过XmlSerializer的行为没有太多控制,所以我们不要试图阻止其序列化的空值类型。 相反,只取序列化输出和替换使用正则表达式一个空字符串不需要的元素。 使用(在C#)的模式是:

<\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;
        }
    }
}

我希望这有帮助。



Answer 8:

写这样的,其确切的输出是很重要的代码的最简单方法是:

  1. 撰写描述您的确切所需格式的XML架构。
  2. 使用转换你的架构类xsd.exe
  3. 将您的类回模式(使用xsd.exe再次),并检查其对你的原来的架构,以确保串行正确再现希望在每次的行为。

调整和重复,直到你有工作的代码。

如果你不知道确切的数据类型,最初使用的,开始第3步,而不是第1步,然后调整。

IIRC,你的例子中,你几乎肯定会结束与Specified因为你已经得到的物性,但让他们对你肯定比手动编写它们产生的。 :-)



Answer 9:

如果你让你想要连载类实现IXmlSerializable的,你可以使用下面的作家。 请注意,您将需要实现一个读者,但那不是太硬。

    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();
            }
        }
    }


Answer 10:

标记与所述元素[的XmlElement(“的ElementName”,ISNULLABLE =假)]空值将被省略。



文章来源: How to exclude null properties when using XmlSerializer