LinqToXml does not handle elements having zero length as expected

According to W3C standards, if you have a null element with a null value, you should format it like this:

<myNillableElement xsi:nil="true" />

      

But if you use this LinqToXml statement ...

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

      

... the resulting XML ...

<myNillableElement />

      

... which is not valid. And not just invalid according to W3C, invalid according to Microsoft using XML / XSD authentication. So, next time you validate your XML you will get errors.

Is it missing some switch that can enable correct handling of nillable items?

Thank.

+2


source to share


3 answers


LINQ to XML is mostly not schema-specific - it allows tree validation, but it doesn't infer any specific semantics from that. Your mistake is that it null

should somehow always appear on xsi:nil

. There is no such requirement in the W3C specifications (rather, obviously, because they do not cover any types of language bindings).



In particular, the constructor XElement

that you call actually takes a type argument object[]

, which is a list of children - there is no reason the pass null

should have anything to do with xsi:nil

. Anyway, how is LINQ to XML supposed to know that you are creating XML that is valid according to some schema, and what one particular element in that schema has nilled="true"

?

+3


source


You can also do something like this using 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)
    );

      

+2


source


Hope this isn't a perfect answer, but I've written a few extension methods to make it a little easier to work 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;
    }
}

      

Usage example

// "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");

      

+1


source







All Articles