Запретить <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); }
}