According to W3C standards, if you have a nillable element with a nil value, you are supposed to format it like this:
LINQ to XML is mostly not schema-aware - it lets you validate the tree, but it doesn't derive any particular semantics from that. Your mistake is believing that null
should somehow always map to xsi:nil
. There's no such requirement in W3C specs (rather obviously, because they do not cover any kinds of language bindings).
In particular, XElement
constructor that you call actually takes an argument of type object[]
, which is a list of children - there's no reason why passing null
to that should have any relevance to xsi:nil
. In any case, how is LINQ to XML supposed to know that you're producing XML that is valid according to some schema, and that one particular element in this schema has nilled="true"
?
You could also do something like this, taking advantage of the null coalescing operator:
public static object Nil
{
get
{
// **I took a guess at the syntax here - you should double check.**
return new XAttribute(Xsi + "nil", true);
}
}
// ......
object nullableContent = ...;
element.Add(
new XElement(NS + "myNillableElement", nullableContent ?? Nil)
);
Hopefully, this is not the ideal answer, but I wrote a couple extension methods to at least make it a little easier to deal with nillable elements in LinqToXml.
Extension Methods:
public static class XElementExtensions
{
private static XName _nillableAttributeName = "{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 hasNillableAttribute = element.Attribute(_nillableAttributeName) != null;
if (string.IsNullOrEmpty(element.Value))
{
if (!hasNillableAttribute)
element.Add(new XAttribute(_nillableAttributeName, true));
}
else
{
if (hasNillableAttribute)
element.Attribute(_nillableAttributeName).Remove();
}
return element;
}
}
Example Usage
// "nil" attribute will be added
element.Add(
new XElement(NS + "myNillableElement", null)
.MakeNillable();
// no attribute will be added
element.Add(
new XElement(NS + "myNillableElement", "non-null string")
.MakeNillable();
// "nil" attribute will be added (if not already present)
element.SetNillableElementValue(NS + "myNillableElement", null);
// no attribute will be added (and will be removed if necessary)
element.SetNillableElementValue(NS + "myNillableElement", "non-null string");