Запретить <xsi: nil = "true"> для типов значений Nullable при сериализации в XML

Я добавил некоторые типы значений Nullable в мой сериализуемый класс. Я выполняю сериализацию, используя XmlSerializer но когда значение установлено в nullЯ получаю пустой узел с xsi:nil="true", Это правильное поведение, как я обнаружил в Xsi:nil Поддержка привязки атрибутов.

Есть ли способ отключить эту опцию, чтобы ничего не выводилось, когда тип значения null?

5 ответов

Я должен был добавить ShouldSerialize метод для каждого обнуляемого значения.

[Serializable]
public class Parent
{
    public int? Element { get; set; }

    public bool ShouldSerializeElement() => Element.HasValue;
}

У меня была такая же проблема... вот одно из мест, где я читал об обработке типов значений Nullable при сериализации в XML: /questions/27458316/serializirovat-obnulyaemyij-int

они упоминают об использовании встроенных шаблонов, таких как создание дополнительных свойств для типов значений Nullable. как для свойства с именем

public int? ABC

Вы должны либо добавить либо public bool ShouldSerializeABC() {return ABC.HasValue;} или публичный bool ABCSpecified { get { return ABC.HasValue; } }

я только сериализовал в xml, чтобы отправить в sql хранимый процесс, поэтому я тоже избегал менять свои классы. Я делаю [not(@xsi:nil)] проверьте все обнуляемые элементы в моем запросе.value().

Я обнаружил, что публичный бул ABCSpecified был единственным, который работал с.NET 4.0. Я также должен был добавить XmlIgnoreAttribute

Вот мое полное решение для подавления строки с именем ABC в файле Web Reference Resource.cs:

// backing fields
private string abc;
private bool abcSpecified; // Added this - for client code to control its serialization

// serialization of properties
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
public string ABC
{
    get
    {
        return this.abc;
    }
    set
    {
        this.abc= value;
    }
}

// Added this entire property procedure
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool ABCSpecified
{
    get
    {
        return this.abcSpecified;
    }
    set
    {
        this.abcSpecified = value;
    }
}

Это, вероятно, наименее сложный ответ, но я решил его с помощью простой замены строки.

.Replace ("xsi: nil = \" true \ "", "");

В любом случае, я сериализуюсь в первую очередь. Я могу сохранить в файл позже.

Он сохраняет все мои XmlWriterSettings нетронутыми. Еще одно решение я нашел ее испортил это:)

    private static string Serialize<T>(T details)
    {
        var serializer = new XmlSerializer(typeof(T));
        using (var ms = new MemoryStream())
        {
            var settings = new XmlWriterSettings
            {
                Encoding = Encoding.GetEncoding("ISO-8859-1"),
                NewLineChars = Environment.NewLine,
                ConformanceLevel = ConformanceLevel.Document,
                Indent = true,
                OmitXmlDeclaration = true
            };

            using (var writer = XmlWriter.Create(ms, settings))
            {
                serializer.Serialize(writer, details);
                return Encoding.UTF8.GetString(ms.ToArray()).Replace(" xsi:nil=\"true\" ", "");
            }
        }
    }

Все мета-методы, такие как Specified или ShouldSerialize, являются просто плохим программным дизайном XML-структуры Microsoft.Net. Это становится еще сложнее, если у вас нет прямого доступа к классам, которые вы хотите сериализовать.

В их методе сериализации они должны просто добавить атрибут типа "ignoreNullable".

Мой текущий обходной путь сериализует xml и затем просто удаляет все узлы, имеющие nil="true", используя следующую функцию.

/// <summary>
/// Remove optional nullabe xml nodes from given xml string using given scheme prefix.
/// 
/// In other words all nodes that have 'xsi:nil="true"' are being removed from document.
/// 
/// If prefix 'xmlns:xsi' is not found in root element namespace input xml content is returned.
/// </summary>
/// <param name="xmlContent"></param>
/// <param name="schemePrefix">Scheme location prefix</param>
/// <returns></returns>
public static String RemoveNilTrue(String xmlContent, String schemePrefix = "xsi")
{
    XmlDocument xmlDocument = new XmlDocument();
    xmlDocument.LoadXml(xmlContent);

    XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmlDocument.NameTable);

    bool schemeExist = false;

    foreach (XmlAttribute attr in xmlDocument.DocumentElement.Attributes)
    {
        if (attr.Prefix.Equals("xmlns", StringComparison.InvariantCultureIgnoreCase)
            && attr.LocalName.Equals(schemePrefix, StringComparison.InvariantCultureIgnoreCase))
        {
            nsMgr.AddNamespace(attr.LocalName, attr.Value);
            schemeExist = true;
            break;
        }
    }

    // scheme exists - remove nodes
    if (schemeExist)
    {
        XmlNodeList xmlNodeList = xmlDocument.SelectNodes("//*[@" + schemePrefix + ":nil='true']", nsMgr);

        foreach (XmlNode xmlNode in xmlNodeList)
            xmlNode.ParentNode.RemoveChild(xmlNode);

        return xmlDocument.InnerXml;
    }
    else
        return xmlContent;
}

Я сделал это так:

    private bool retentionPeriodSpecified;
    private Nullable<int> retentionPeriod;

    [XmlElement(ElementName = "retentionPeriod", IsNullable = true, Order = 14)]
    public Nullable<int> RetentionPeriod { get => retentionPeriod; set => retentionPeriod = value; }

    [System.Xml.Serialization.XmlIgnore()]
    public bool RetentionPeriodSpecified
    {
        get { return !(retentionPeriod is null); }
    }
Другие вопросы по тегам