C# LinqToXml未按预期处理可为零的元素
根据W3C标准,如果您有一个具有nil值的nillable元素,则应该将其格式化如下:C# LinqToXml未按预期处理可为零的元素,c#,xml,xsd,schema,linq-to-xml,C#,Xml,Xsd,Schema,Linq To Xml,根据W3C标准,如果您有一个具有nil值的nillable元素,则应该将其格式化如下: <myNillableElement xsi:nil="true" /> …生成的XML是 <myNillableElement /> …这是无效的。而且不仅根据W3C是无效的,根据微软自己的XML/XSD验证器也是无效的。因此,下次验证XML时,会出现错误 我是否遗漏了一些可以正确处理零元素的开关 谢谢。希望这不是一个理想的答案,但我编写了两个扩展方法,至少使处理LinqTo
<myNillableElement xsi:nil="true" />
…生成的XML是
<myNillableElement />
…这是无效的。而且不仅根据W3C是无效的,根据微软自己的XML/XSD验证器也是无效的。因此,下次验证XML时,会出现错误
我是否遗漏了一些可以正确处理零元素的开关
谢谢。希望这不是一个理想的答案,但我编写了两个扩展方法,至少使处理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");
LINQtoXML基本上是不支持模式的——它允许您验证树,但它不会从中派生任何特定的语义。您的错误是认为
null
应该以某种方式始终映射到xsi:nil
。W3C规范中没有这样的要求(很明显,因为它们不包括任何类型的语言绑定)
特别是,您调用的
XElement
构造函数实际上接受类型为object[]
的参数,这是一个子类列表-没有理由将null
传递给该构造函数与xsi:nil
有任何关联。在任何情况下,LINQ to XML如何知道您正在生成的XML根据某种模式是有效的,并且此模式中的一个特定元素具有nilled=“true”
?您也可以这样做,利用空合并操作符:
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
,因为属性需要添加、删除或保持原样。谢谢你的回答……我想我会编辑文章的标题,因为你让我相信我观察到的并不是真的不正确的行为。不过,如果LinqToXml有一组支持模式的类就好了,这将把空字符串视为null,这可能是不可取的。也就是说,new-XElement(“Name”,null)
和new-XElement(“Name”,null)
都将被标记为nil
@MattMitchell,有趣的一点,但我想我是这样编码的,因为使用XElement
表示空元素值是不可能的。即使您执行了new-XElement(name,null)
,Value
属性也将是string.Empty
,而不是null
。因此,对于字符串,您确实失去了区分空值和空值的能力,但至少值类型(如int
)可以按预期工作。如果您能想到字符串的解决方法,请让我知道。对于.SetNillableElementValue
的情况,您可以检查提供的值是否为null
,如果是,请添加nillable属性。正如您所说,在事实之后(例如在MakeNillable
案例中),无法确定源值是否为null。
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)
);