【问题标题】:LinqToXml does not handle nillable elements as expectedLinqToXml 没有按预期处理 nillable 元素
【发布时间】:2010-03-08 18:54:04
【问题描述】:

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

<myNillableElement xsi:nil="true" />

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

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

...生成的 XML 是...

<myNillableElement />

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

我是否缺少一些可以正确处理可空元素的开关?

谢谢。

【问题讨论】:

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


    【解决方案1】:

    LINQ to XML 大多不支持模式 - 它允许您验证树,但它不会从中派生任何特定的语义。您的错误是认为null 应该以某种方式始终映射到xsi:nil。 W3C 规范中没有这样的要求(很明显,因为它们不涵盖任何类型的语言绑定)。

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

    【讨论】:

    • 感谢您的回答...我想我会编辑帖子的标题,因为您已经让我相信我所观察到的并不是真正不正确的行为。不过,如果 LinqToXml 有一组可感知模式的类,那就太好了。
    【解决方案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)
        );
    

    【讨论】:

    • 非常漂亮!我以前没有遇到过??。不过,我认为仍然需要扩展方法来处理 SetElementValue,因为该属性要么需要添加、删除,要么保持原样。
    【解决方案3】:

    希望这不是理想的答案,但我编写了几个扩展方法,至少可以更轻松地处理 LinqToXml 中的可空元素。

    扩展方法:

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

    【讨论】:

    • 这会将空白字符串视为 null,这可能是不可取的。 IE。 new XElement("Name", null)new XElement("Name", "") 都将被标记为 nil
    • @MattMitchell,有趣的一点,但我想我是这样编码的,因为根本不可能使用XElement 来表示空元素值。即使您使用new XElement(name, null)Value 属性也将是string.Empty,而不是null。因此,对于字符串,您确实失去了区分空值和空值的能力,但至少值类型(如 int)可以按预期工作。如果您能想到字符串的解决方法,请告诉我。
    • 对于.SetNillableElementValue 的情况,您可以检查提供的value 是否为null,如果是,则添加可空属性。正如您所说,事后(例如在MakeNillable 案例中)无法确定源值是否为空。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-22
    • 2023-01-18
    • 2018-05-14
    • 2017-12-10
    • 2018-02-10
    • 1970-01-01
    相关资源
    最近更新 更多