Xml серіалізація - приховати нульові значення


128

Використовуючи стандартний серіалізатор .NET Xml, чи можна приховати всі нульові значення? Нижче наведено приклад результатів мого класу. Я не хочу виводити нульові цілі числа, якщо вони встановлені на нуль.

Поточний вихід 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>

Відповіді:


255

Ви можете створити функцію за допомогою шаблону, ShouldSerialize{PropertyName}який повідомляє 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>

9
Одне слово: Дивовижно! MSDN ShouldSerialize
схема

7
Шаблон ShouldSerialize працює лише в тому випадку, якщо властивість не позначено атрибутом XmlAttribute (я вважав, що це має працювати, тому що атрибут може бути необов'язковим, але він не робить).
Маце

@Matze цікаво, я цього не пробував. Я б також припустив, що це спрацює.
Кріс Тейлор

@ChrisTaylor Так; Я припускав те саме. Найскладнішим було те, що створення екземпляра XmlSerializer не вдалося (через помилку при відображенні типу), поки я не видалив XmlAttribute зі зведеного властивості int.
Маце

2
@PierredeLESPINAY - від візуальної студії 2015 року і вище ви можете використовувати: public bool ShouldSerializeAge () => Age.HasValue;
RooiWillie

34

Крім того, що написав Кріс Тейлор: якщо у вас є щось серіалізоване як атрибут, ви можете мати властивість свого класу, іменовану {PropertyName}Specifiedдля управління, чи слід його серіалізувати. У коді:

public class MyClass
{
    [XmlAttribute]
    public int MyValue;

    [XmlIgnore]
    public bool MyValueSpecified;
}

Будьте обережні, {PropertyName}Specifiedатрибути повинні мати тип bool.
sinsedrix

30

Він існує властивість, що називається XmlElementAttribute.IsNullable

Якщо для властивості IsNullable встановлено значення true, атрибут xsi: nil генерується для членів класу, яким було встановлено нульову посилання.

Наступний приклад показує поле із XmlElementAttributeзастосованим до нього, а властивість IsNullable встановлено на false.

public class MyClass
{
   [XmlElement(IsNullable = false)]
   public string Group;
}

Ви можете поглянути на інших, XmlElementAttributeщоб змінити імена при серіалізації тощо.


11
На жаль, це працює лише для еталонних типів, а не для типів значень або їх нульових аналогів.
Вінсент Сальс

3
@VincentSels вірно. MSDN каже: Ви не можете застосувати властивість IsNullable до члена, введеного як тип значення, оскільки тип значення не може містити null. Крім того, ви не можете встановити це властивість значення false для змінних типів значення. Коли такі типи є недійсними, вони будуть серіалізовані, встановивши xsi: nil на true.
bouvierr

12

Можна визначити деякі значення за замовчуванням, і це запобігає серіалізації полів.

    [XmlElement, DefaultValue("")]
    string data;

    [XmlArray, DefaultValue(null)]
    List<string> data;

На жаль, це не працює для змінних типів значення
bubi

2

Я вважаю за краще створювати власний 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;
    }

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

1

У моєму випадку всі нульові змінні / елементи були типу String. Отже, я просто здійснив перевірку і призначив їм рядок.Порожній у випадку 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

1
Це рішення дуже обмежене і працює лише з рядком. Для інших типів порожній рядок як і раніше є значенням. Деякі аналізатори намагаються знайти атрибут, а якщо їх знайдено, намагаються перетворити значення в цільовий тип. Для таких аналізаторів відсутність атрибута означає null, а якщо є атрибут, то він повинен мати дійсне значення.
ZafarYousafi
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.