LinqToXml不按预期处理可为空的元素

时间:2009-09-01 22:13:40

标签: c# xml xsd schema linq-to-xml

根据W3C标准,如果你有一个nil值的nillable元素,你应该像这样格式化:

<myNillableElement xsi:nil="true" />

但是如果你使用这个LinqToXml语句......

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

......生成的XML是......

<myNillableElement />

......这是无效的。根据W3C,不仅无效,根据微软自己的XML / XSD验证器无效。因此,下次验证XML时,会出现错误。

我是否遗漏了一些能够正确处理可支付元素的开关?

感谢。

3 个答案:

答案 0 :(得分:3)

LINQ to XML主要不支持模式 - 它允许您验证树,但它不会从中获取任何特定的语义。你的错误是相信null应该总是映射到xsi:nil。 W3C规范中没有这样的要求(很明显,因为它们不包括任何类型的语言绑定)。

特别是,您调用的XElement构造函数实际上采用类型为object[]的参数,这是一个子列表 - 没有理由将null传递给它应该具有任何相关性到xsi:nil。在任何情况下,LINQ to XML如何知道您根据某些模式生成有效的XML,并且此模式中的一个特定元素具有nilled="true"

答案 1 :(得分:2)

你也可以做这样的事情,利用空合并运算符:

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 :(得分:1)

希望这不是理想的答案,但我写了几个扩展方法,至少可以让它更容易处理LinqToXml中的nillable元素。

扩展方法:

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;
    }
}

使用示例

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