问题
According to W3C standards, if you have a nillable element with a nil value, you are supposed to 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 is...
<myNillableElement />
...which is invalid. And not just invalid according to W3C, invalid according to Microsoft's own XML/XSD validator. So, next time you validate your XML, you get errors.
Am I missing some switch that can turn on correct handling of nillable elements?
Thanks.
回答1:
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"
?
回答2:
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)
);
回答3:
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");
来源:https://stackoverflow.com/questions/1364917/linqtoxml-does-not-handle-nillable-elements-as-expected