Serialisasi Xml - Sembunyikan nilai null

128

Saat menggunakan standar .NET Xml Serializer, apakah ada cara saya bisa menyembunyikan semua nilai nol? Di bawah ini adalah contoh dari output kelas saya. Saya tidak ingin menampilkan bilangan bulat nullable jika mereka diatur ke nol.

Output Xml saat ini:

<?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>

Apa yang saya inginkan:

<?xml version="1.0" encoding="utf-8"?>
<myClass>
   <myOtherInt>-1</myOtherInt>
</myClass>
Pendidikan Guru
sumber

Jawaban:

255

Anda dapat membuat fungsi dengan pola ShouldSerialize{PropertyName}yang memberi tahu XmlSerializer jika harus membuat serial anggota atau tidak.

Misalnya, jika properti kelas MyNullableIntAnda dipanggil, Anda bisa memilikinya

public bool ShouldSerializeMyNullableInt() 
{
  return MyNullableInt.HasValue;
}

Ini adalah contoh lengkap

public class Person
{
  public string Name {get;set;}
  public int? Age {get;set;}
  public bool ShouldSerializeAge()
  {
    return Age.HasValue;
  }
}

Serialized dengan kode berikut

Person thePerson = new Person(){Name="Chris"};
XmlSerializer xs = new XmlSerializer(typeof(Person));
StringWriter sw = new StringWriter();
xs.Serialize(sw, thePerson);

Hasil dalam XML followng - Perhatikan tidak ada Umur

<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Chris</Name>
</Person>
Chris Taylor
sumber
9
Satu kata: Luar biasa! MSDN ShouldSerialize
scheien
7
Pola ShouldSerialize hanya berfungsi, jika properti tidak ditandai dengan atribut XmlAttribute (saya pikir ini harus bekerja, karena atribut bisa opsional, tetapi tidak).
Matze
@Matze menarik, saya belum mencobanya. Saya juga akan menganggap itu akan berhasil.
Chris Taylor
@ ChrisTaylor Ya; Saya berasumsi sama. Yang sulit adalah bahwa pembuatan instance XmlSerializer gagal (karena kesalahan ketika mencerminkan jenis) sampai saya menghapus XmlAttribute dari int-property nullable.
Matze
2
@PierredeLESPINAY - Dari visual studio 2015 dan lebih tinggi, Anda dapat menggunakan: bool publik ShouldSerializeAge () => Age.HasValue;
RooiWillie
34

Sebagai tambahan terhadap apa yang ditulis oleh Chris Taylor: jika Anda memiliki sesuatu yang diserialisasi sebagai atribut, Anda dapat memiliki properti di kelas Anda yang {PropertyName}Specifiedakan dikontrol untuk menentukan apakah harus diserialisasi. Dalam kode:

public class MyClass
{
    [XmlAttribute]
    public int MyValue;

    [XmlIgnore]
    public bool MyValueSpecified;
}
Daniel Rose
sumber
Hati-hati, {PropertyName}Specifiedatribut harus bertipe bool.
sinsedrix
30

Itu ada properti yang disebut XmlElementAttribute.IsNullable

Jika properti IsNullable disetel ke true, atribut xsi: nil dihasilkan untuk anggota kelas yang telah disetel ke referensi nol.

Contoh berikut memperlihatkan bidang dengan XmlElementAttributediterapkan ke itu, dan properti IsNullable disetel ke false.

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

Anda dapat melihat-lihat orang lain XmlElementAttributeuntuk mengubah nama dalam serialisasi dll.

JPBlanc
sumber
11
Sayangnya, ini hanya berfungsi untuk tipe referensi, bukan untuk tipe nilai atau rekan Nullable mereka.
Vincent Sels
3
@VincentSels benar. MSDN mengatakan: Anda tidak bisa menerapkan properti IsNullable ke anggota yang diketik sebagai tipe nilai karena tipe nilai tidak boleh mengandung nol. Selain itu, Anda tidak dapat mengatur properti ini menjadi false untuk tipe nilai yang dapat dibatalkan. Ketika jenis seperti itu nol, mereka akan diserialkan dengan mengatur xsi: nil ke true.
bouvierr
12

Anda dapat menentukan beberapa nilai default dan mencegah bidang menjadi serial.

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

    [XmlArray, DefaultValue(null)]
    List<string> data;
MichaelJadi
sumber
Sayangnya, ini tidak berfungsi untuk tipe nilai yang dapat
dibatalkan
2

Saya lebih suka membuat xml saya sendiri tanpa tag yang dibuat secara otomatis. Dalam hal ini saya dapat mengabaikan membuat node dengan nilai nol:

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;
    }
Durga Nunna
sumber
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
sumber
1

Dalam kasus saya variabel / elemen yang dapat dibatalkan semua adalah tipe String. Jadi, saya hanya melakukan pemeriksaan dan menugaskan mereka string.Empty dalam kasus NULL. Dengan cara ini saya menyingkirkan atribut nil dan xmlns yang tidak perlu (p3: nil = "true" xmlns: p3 = "http://www.w3.org/2001/XMLSchema-instance)

// Example:

myNullableStringElement = varCarryingValue ?? string.Empty

// OR

myNullableStringElement = myNullableStringElement ?? string.Empty
Sagar
sumber
1
Solusi ini sangat terbatas dan hanya berfungsi dengan string. Untuk jenis lain string kosong masih bernilai. Beberapa parser mencoba mencari atribut dan jika ditemukan cobalah untuk mengubah nilai menjadi tipe target. Untuk parser seperti itu, atribut yang hilang berarti nol dan jika ada atribut maka itu harus memiliki nilai yang valid.
ZafarYousafi