LinqToXml ne gère pas les éléments nillables comme prévu

Selon les normes du W3C, si vous avez un élément nillable avec une valeur nulle, vous devez le formater comme ceci:

 

Mais si vous utilisez cette instruction LinqToXml …

 element.Add( new XElement(ns + "myNillableElement", null); 

… le XML résultant est …

  

… qui est invalide. Et pas seulement invalide selon le W3C, invalide selon le validateur XML / XSD de Microsoft. Donc, la prochaine fois que vous validez votre XML, vous obtenez des erreurs.

Me manque-t-il un interrupteur pouvant activer la manipulation correcte des éléments nillables?

Merci.

LINQ to XML n’est généralement pas sensible au schéma – il vous permet de valider l’arbre, mais il n’en tire aucune sémantique particulière. Votre erreur est de croire que null devrait toujours correspondre à xsi:nil . Les spécifications du W3C ne prévoient aucune exigence de ce type (bien évidemment, car elles ne couvrent aucun type de corrélation de langage).

En particulier, le constructeur XElement que vous appelez prend en fait un argument de type object[] , qui est une liste d’enfants. Il n’y a aucune raison pour laquelle passer null à cela ne devrait avoir aucune pertinence pour xsi:nil . Dans tous les cas, comment LINQ to XML est-il censé savoir que vous produisez du XML valide selon certains schémas et qu’un élément particulier de ce schéma a nilled="true" ?

Vous pouvez également faire quelque chose comme ceci, en tirant parti de l’opérateur de coalescence nul:

 public static object Nil { get { // **I took a guess at the syntax here - you should double check.** return new XAtsortingbute(Xsi + "nil", true); } } // ...... object nullableContent = ...; element.Add( new XElement(NS + "myNillableElement", nullableContent ?? Nil) ); 

Espérons que ce n’est pas la solution idéale, mais j’ai écrit quelques méthodes d’extension pour au moins faciliter un peu la gestion des éléments nillables dans LinqToXml.

Méthodes d’extension:

 public static class XElementExtensions { private static XName _nillableAtsortingbuteName = "{http://www.w3.org/2001/XMLSchema-instance}nil"; public static void SetNillableElementValue(this XElement parentElement, XName elementName, object value) { parentElement.SetElementValue(elementName, value); parentElement.Element(elementName).MakeNillable(); } public static XElement MakeNillable(this XElement element) { var hasNillableAtsortingbute = element.Atsortingbute(_nillableAtsortingbuteName) != null; if (ssortingng.IsNullOrEmpty(element.Value)) { if (!hasNillableAtsortingbute) element.Add(new XAtsortingbute(_nillableAtsortingbuteName, true)); } else { if (hasNillableAtsortingbute) element.Atsortingbute(_nillableAtsortingbuteName).Remove(); } return element; } } 

Exemple d’utilisation

 // "nil" atsortingbute will be added element.Add( new XElement(NS + "myNillableElement", null) .MakeNillable(); // no atsortingbute will be added element.Add( new XElement(NS + "myNillableElement", "non-null ssortingng") .MakeNillable(); // "nil" atsortingbute will be added (if not already present) element.SetNillableElementValue(NS + "myNillableElement", null); // no atsortingbute will be added (and will be removed if necessary) element.SetNillableElementValue(NS + "myNillableElement", "non-null ssortingng");