XML-Serialisierung - Nullwerte ausblenden

128

Kann ich bei Verwendung eines standardmäßigen .NET Xml-Serializers alle Nullwerte ausblenden? Das Folgende ist ein Beispiel für die Ausgabe meiner Klasse. Ich möchte die nullbaren Ganzzahlen nicht ausgeben, wenn sie auf null gesetzt sind.

Aktuelle XML-Ausgabe:

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

Was ich möchte:

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

Antworten:

254

Sie können eine Funktion mit dem Muster erstellen, ShouldSerialize{PropertyName}die dem XmlSerializer mitteilt, ob das Mitglied serialisiert werden soll oder nicht.

Wenn Ihre Klasseneigenschaft beispielsweise aufgerufen wird MyNullableInt, könnten Sie haben

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

Hier ist ein vollständiges Beispiel

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

Serialisiert mit dem folgenden Code

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

Ergebnisse in der folgenden XML - Beachten Sie, dass es kein Alter gibt

<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Chris</Name>
</Person>
Chris Taylor
quelle
9
Ein Wort: Super! MSDN ShouldSerialize
scheien
7
Das ShouldSerialize-Muster funktioniert nur, wenn die Eigenschaft nicht mit einem XmlAttribute-Attribut markiert ist (ich dachte, dies sollte funktionieren, da ein Attribut optional sein könnte, aber nicht).
Matze
@ Matze interessant, das habe ich nicht ausprobiert. Ich hätte auch angenommen, dass es funktionieren würde.
Chris Taylor
@ ChrisTaylor Ja; Ich nahm das gleiche an. Das Knifflige war, dass die Erstellung der XmlSerializer-Instanz fehlgeschlagen ist (aufgrund eines Fehlers beim Reflektieren des Typs), bis ich das XmlAttribute aus der nullbaren int-Eigenschaft entfernt habe.
Matze
2
@PierredeLESPINAY - Ab Visual Studio 2015 können Sie Folgendes verwenden: public bool ShouldSerializeAge () => Age.HasValue;
RooiWillie
34

Zusätzlich zu dem, was Chris Taylor geschrieben hat: Wenn Sie etwas als Attribut serialisiert haben, können Sie eine Eigenschaft in Ihrer Klasse benennen, um {PropertyName}Specifiedzu steuern, ob es serialisiert werden soll. In Code:

public class MyClass
{
    [XmlAttribute]
    public int MyValue;

    [XmlIgnore]
    public bool MyValueSpecified;
}
Daniel Rose
quelle
Seien Sie vorsichtig, {PropertyName}SpecifiedAttribute müssen vom Typ bool sein.
Sinsedrix
30

Es existiert eine Eigenschaft namens XmlElementAttribute.IsNullable

Wenn die IsNullable-Eigenschaft auf true festgelegt ist, wird das Attribut xsi: nil für Klassenmitglieder generiert, die auf eine Nullreferenz festgelegt wurden.

Das folgende Beispiel zeigt ein Feld, auf das XmlElementAttributedas Feld angewendet wurde, und die IsNullable-Eigenschaft ist auf false gesetzt.

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

Sie können nach anderen suchen, XmlElementAttributeum Namen in der Serialisierung usw. zu ändern.

JPBlanc
quelle
11
Leider funktioniert dies nur für Referenztypen, nicht für Werttypen oder deren Nullable-Gegenstücke.
Vincent Sels
3
@ VincentSels ist korrekt. MSDN sagt: Sie können die IsNullable-Eigenschaft nicht auf ein Mitglied anwenden, das als Werttyp eingegeben wurde, da ein Werttyp keinen Nullwert enthalten kann. Darüber hinaus können Sie diese Eigenschaft für nullwertfähige Werttypen nicht auf false setzen. Wenn solche Typen null sind, werden sie serialisiert, indem xsi: nil auf true gesetzt wird.
Bouvierr
12

Sie können einige Standardwerte definieren und verhindern, dass die Felder serialisiert werden.

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

    [XmlArray, DefaultValue(null)]
    List<string> data;
MichaelSo
quelle
Leider funktioniert dies nicht für
nullbare Werttypen
2

Ich bevorzuge es, meine eigene XML ohne automatisch generierte Tags zu erstellen. In diesem Fall kann ich das Erstellen der Knoten mit Nullwerten ignorieren:

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
quelle
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
quelle
1

In meinem Fall waren die nullbaren Variablen / Elemente alle vom Typ String. Also habe ich einfach eine Prüfung durchgeführt und ihnen einen String zugewiesen. Leer bei NULL. Auf diese Weise habe ich die unnötigen Attribute nil und xmlns entfernt (p3: nil = "true" xmlns: p3 = "http://www.w3.org/2001/XMLSchema-instance)

// Example:

myNullableStringElement = varCarryingValue ?? string.Empty

// OR

myNullableStringElement = myNullableStringElement ?? string.Empty
Sagar
quelle
1
Diese Lösung ist sehr begrenzt und funktioniert nur mit String. Für andere Typen ist eine leere Zeichenfolge immer noch ein Wert. Einige Parser versuchen, ein Attribut zu finden, und wenn gefunden, versuchen sie, den Wert in einen Zieltyp zu konvertieren. Für solche Parser bedeutet fehlendes Attribut null, und wenn es ein Attribut gibt, muss es einen gültigen Wert haben.
ZafarYousafi