Serializzazione XML - Nascondi valori null


128

Quando si utilizza un serializzatore Xml .NET standard, è possibile nascondere tutti i valori null? Di seguito è riportato un esempio dell'output della mia classe. Non voglio produrre numeri interi nullable se sono impostati su null.

Uscita Xml corrente:

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

Quello che voglio:

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

Risposte:


255

È possibile creare una funzione con il modello ShouldSerialize{PropertyName}che indica a XmlSerializer se deve serializzare il membro o meno.

Ad esempio, se si chiama la proprietà della classe, MyNullableIntsi potrebbe avere

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

Ecco un esempio completo

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

Serializzato con il seguente codice

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

Risultati nel seguente XML - Notare che non esiste Age

<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Chris</Name>
</Person>

9
Una sola parola: fantastico! MSDN ShouldSerialize
scheien

7
Il modello ShouldSerialize funziona solo se la proprietà non è contrassegnata con un attributo XmlAttribute (ho pensato che dovrebbe funzionare, perché un attributo potrebbe essere facoltativo, ma non funziona).
Matze,

@Matze interessante, non l'ho provato. Avrei anche pensato che avrebbe funzionato.
Chris Taylor,

@ChrisTaylor Sì; Ho assunto lo stesso. La cosa difficile è che la creazione dell'istanza XmlSerializer non è riuscita (a causa di un errore nel riflettere il tipo) fino a quando non ho rimosso XmlAttribute dalla proprietà int nullable.
Matze,

2
@PierredeLESPINAY - Da Visual Studio 2015 e versioni successive, è possibile utilizzare: bool pubblico ShouldSerializeAge () => Age.HasValue;
RooiWillie,

34

Oltre a ciò che ha scritto Chris Taylor: se hai qualcosa di serializzato come attributo, puoi avere una proprietà nella tua classe chiamata {PropertyName}Specifiedper controllare se dovrebbe essere serializzata. Nel codice:

public class MyClass
{
    [XmlAttribute]
    public int MyValue;

    [XmlIgnore]
    public bool MyValueSpecified;
}

Attenzione, gli {PropertyName}Specifiedattributi devono essere di tipo bool.
sinsedrix,

30

Esiste una proprietà chiamata XmlElementAttribute.IsNullable

Se la proprietà IsNullable è impostata su true, l'attributo xsi: nil viene generato per i membri della classe che sono stati impostati su riferimento null.

L'esempio seguente mostra un campo con XmlElementAttributeapplicato ad esso e la proprietà IsNullable impostata su false.

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

Puoi dare un'occhiata agli altri XmlElementAttributeper cambiare i nomi nella serializzazione ecc.


11
Sfortunatamente, questo funziona solo per i tipi di riferimento, non per i tipi di valore o le loro controparti Nullable.
Vincent Sels,

3
@VincentSels è corretto. MSDN dice: Non è possibile applicare la proprietà IsNullable a un membro digitato come tipo di valore poiché un tipo di valore non può contenere null. Inoltre, non è possibile impostare questa proprietà su false per i tipi di valore nullable. Quando tali tipi sono nulli, verranno serializzati impostando xsi: nil su true.
Bouvierr,

12

È possibile definire alcuni valori predefiniti e impedisce la serializzazione dei campi.

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

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

Sfortunatamente, questo non funziona per i tipi di valore nullable
bubi

2

Preferisco creare il mio xml senza tag generati automaticamente. In questo posso ignorare la creazione di nodi con valori null:

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

Nel mio caso le variabili / elementi nullable erano tutti di tipo String. Quindi, ho semplicemente eseguito un controllo e assegnato loro stringa.Empty in caso di NULL. In questo modo mi sono liberato degli inutili attributi nil e xmlns (p3: nil = "true" xmlns: p3 = "http://www.w3.org/2001/XMLSchema-instance)

// Example:

myNullableStringElement = varCarryingValue ?? string.Empty

// OR

myNullableStringElement = myNullableStringElement ?? string.Empty

1
Questa soluzione è molto limitata e funziona solo con la stringa. Per altri tipi, la stringa vuota è ancora un valore. Alcuni parser tentano di trovare l'attributo e, se trovati, provano a convertire il valore in tipo target. Per tali parser, l'attributo mancante significa null e se esiste un attributo, deve avere un valore valido.
ZafarYousafi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.