Sérialisation XML - Masquer les valeurs nulles

128

Lors de l'utilisation d'un sérialiseur .NET Xml standard, existe-t-il un moyen de masquer toutes les valeurs nulles? Le ci-dessous est un exemple de la sortie de ma classe. Je ne veux pas afficher les entiers Nullable s'ils sont définis sur Null.

Sortie Xml actuelle:

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

Ce que je veux:

<?xml version="1.0" encoding="utf-8"?>
<myClass>
   <myOtherInt>-1</myOtherInt>
</myClass>
GuruMéditation
la source

Réponses:

255

Vous pouvez créer une fonction avec le modèle ShouldSerialize{PropertyName}qui indique au XmlSerializer s'il doit sérialiser le membre ou non.

Par exemple, si votre propriété de classe est appelée, MyNullableIntvous pourriez avoir

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

Voici un échantillon complet

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

Sérialisé avec le code suivant

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

Résultats dans le XML suivant - Remarquez qu'il n'y a pas d'âge

<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Chris</Name>
</Person>
Chris Taylor
la source
9
Un mot: génial! MSDN ShouldSerialize
scheien
7
Le modèle ShouldSerialize ne fonctionne que si la propriété n'est pas marquée d'un attribut XmlAttribute (j'ai pensé que cela devrait fonctionner, car un attribut pourrait être facultatif, mais ce n'est pas le cas).
Matze
@Matze intéressant, je n'ai pas essayé ça. J'aurais également supposé que cela fonctionnerait.
Chris Taylor
@ChrisTaylor Oui; J'ai supposé la même chose. Le problème était que la création de l'instance XmlSerializer a échoué (en raison d'une erreur lors de la réflexion du type) jusqu'à ce que je supprime XmlAttribute de la propriété int nullable.
Matze
2
@PierredeLESPINAY - À partir de Visual Studio 2015 et plus, vous pouvez utiliser: public bool ShouldSerializeAge () => Age.HasValue;
RooiWillie
34

En plus de ce que Chris Taylor a écrit: si vous avez un élément sérialisé en tant qu'attribut, vous pouvez avoir une propriété sur votre classe nommée {PropertyName}Specifiedpour contrôler si elle doit être sérialisée. Dans du code:

public class MyClass
{
    [XmlAttribute]
    public int MyValue;

    [XmlIgnore]
    public bool MyValueSpecified;
}
Daniel Rose
la source
Attention, les {PropertyName}Specifiedattributs doivent être de type bool.
sinsedrix
30

Il existe une propriété appelée XmlElementAttribute.IsNullable

Si la propriété IsNullable est définie sur true, l'attribut xsi: nil est généré pour les membres de classe qui ont été définis sur une référence nulle.

L'exemple suivant montre un champ auquel est XmlElementAttributeappliqué et la propriété IsNullable définie sur false.

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

Vous pouvez consulter les autres XmlElementAttributepour changer les noms lors de la sérialisation, etc.

JPBlanc
la source
11
Malheureusement, cela ne fonctionne que pour les types référence, pas pour les types valeur ou leurs équivalents Nullable.
Vincent Sels
3
@VincentSels est correct. MSDN dit: Vous ne pouvez pas appliquer la propriété IsNullable à un membre tapé comme type valeur car un type valeur ne peut pas contenir null. En outre, vous ne pouvez pas définir cette propriété sur false pour les types de valeur Nullable. Lorsque ces types sont nuls, ils seront sérialisés en définissant xsi: nil sur true.
bouvierr
12

Vous pouvez définir certaines valeurs par défaut et cela empêche les champs d'être sérialisés.

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

    [XmlArray, DefaultValue(null)]
    List<string> data;
MichaelSo
la source
Malheureusement, cela ne fonctionne pas pour les types de valeur Nullable
bubi
2

Je préfère créer mon propre XML sans balises générées automatiquement. En cela, je peux ignorer la création des nœuds avec des valeurs nulles:

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
la source
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
la source
1

Dans mon cas, les variables / éléments Nullable étaient tous de type String. Donc, j'ai simplement effectué une vérification et leur ai assigné une chaîne. Vide en cas de NULL. De cette façon, je me suis débarrassé des attributs inutiles nil et xmlns (p3: nil = "true" xmlns: p3 = "http://www.w3.org/2001/XMLSchema-instance)

// Example:

myNullableStringElement = varCarryingValue ?? string.Empty

// OR

myNullableStringElement = myNullableStringElement ?? string.Empty
Sagar
la source
1
Cette solution est très limitée et ne fonctionne qu'avec de la chaîne. Pour les autres types, une chaîne vide est toujours une valeur. Certains analyseurs essaient de trouver un attribut et, s'il le trouve, essaient de convertir la valeur en type cible. Pour de tels analyseurs, l'attribut manquant signifie null et s'il existe un attribut, il doit avoir une valeur valide.
ZafarYousafi