Сериализация XML - Скрыть нулевые значения

128

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

Текущий вывод 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>
GuruMeditation
источник

Ответы:

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
scheien
7
Шаблон ShouldSerialize работает, только если свойство не помечено атрибутом XmlAttribute (я думал, что это должно работать, потому что атрибут может быть необязательным, но это не так).
Matze
@Matze интересно, я не пробовал. Я бы тоже предположил, что это сработает.
Крис Тейлор,
@ChrisTaylor Да; Я предположил то же самое. Сложность заключалась в том, что создание экземпляра XmlSerializer не удавалось (из-за ошибки при отражении типа) до тех пор, пока я не удалил XmlAttribute из свойства int, допускающего значение NULL.
Matze
2
@PierredeLESPINAY - Начиная с Visual Studio 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чтобы изменить имена в сериализации и т. Д.

JPBlanc
источник
11
К сожалению, это работает только для ссылочных типов, но не для типов значений или их аналогов, допускающих значение NULL.
Винсент Селс
3
@VincentSels верен. В MSDN говорится: свойство IsNullable нельзя применить к члену, набранному как тип значения, поскольку тип значения не может содержать значение null. Кроме того, вы не можете установить для этого свойства значение false для типов значений, допускающих значение NULL. Когда такие типы имеют значение NULL, они будут сериализованы, установив для xsi: nil значение true.
bouvierr
12

Вы можете определить некоторые значения по умолчанию, и это предотвратит сериализацию полей.

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

    [XmlArray, DefaultValue(null)]
    List<string> data;
MichaelSo
источник
К сожалению, это не работает для типов значений, допускающих значение NULL
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;
}
Rauld
источник
1

В моем случае все переменные / элементы, допускающие значение NULL, были строкового типа. Итак, я просто выполнил проверку и присвоил им string.Empty в случае 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
Эти решения очень ограничены и работают только со строкой. Для других типов пустая строка остается значением. Некоторые парсеры пытаются найти атрибут и, если он найден, пытаются преобразовать значение в целевой тип. Для таких парсеров отсутствующий атрибут означает ноль, а если атрибут есть, то он должен иметь допустимое значение.
ZafarYousafi