2009-09-01 93 views
2

根據W3C標準,如果你有一個零值的nillable元素,你應該格式化這樣的:LinqToXml不處理的nillable元素如預期

<myNillableElement xsi:nil="true" /> 

但是如果你使用這個LinqToXml聲明...

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

...生成的XML是...

<myNillableElement /> 

...這是無效的。根據W3C的規定,不僅僅是無效的,根據微軟自己的XML/XSD驗證器無效。所以,下次你驗證你的XML時,你會得到錯誤。

我錯過了一些開關,可以打開nillable元素的正確處理?

謝謝。

回答

3

的LINQ to XML是大都沒有模式感知 - 它可以讓你驗證樹,但它並沒有得到任何特定的語義。你的錯誤是相信null應該總是映射到xsi:nil。 W3C規範中沒有這樣的要求(很明顯,因爲它們不包括任何種類的語言綁定)。

特別是XElement構造函數,你實際上調用需要object[]類型的參數,這是孩子們的名單 - 沒有理由通過null到應該有任何相關性xsi:nil。無論如何,LINQ to XML應該如何知道您正在生成根據某種模式有效的XML,並且此模式中的一個特定元素具有nilled="true"

+0

感謝您的回答......我想我會編輯帖子的標題,因爲您已經確信我所觀察到的並非真正不正確的行爲。不過,如果存在LinqToXml的一組模式感知類,那將會很好。 – devuxer 2009-09-01 23:24:28

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

這將把空字符串爲空,這可能是不理想。即'new XElement(「Name」,null)'和'new XElement(「Name」,「」)'將被標記爲'nil'。 – 2014-04-15 06:52:29

+0

@MattMitchell,有趣的一點,但我認爲我是這樣編碼的,因爲使用'XElement'來表示一個空元素值是不可能的。即使你使用'new XElement(name,null)',Value屬性也是'string.Empty',而不是'null'。因此,對於字符串,您確實喪失了區分空值和空值的能力,但至少值類型(如int)可以像您期望的那樣工作。如果你能想到字符串的解決方法,請告訴我。 – devuxer 2014-04-15 18:07:55

+0

對於'.SetNillableElementValue'的情況,您可以檢查提供的'value'是否爲'null',如果是,則添加nillable屬性。正如你所說的,在事實之後(例如在'MakeNillable'情況下)無法確定源值是否爲空。 – 2014-04-16 08:22:05

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) 
    ); 
+0

非常漂亮!我以前沒有遇到過'??'。不過,我認爲擴展方法仍然需要處理'SetElementValue',因爲該屬性將需要添加,刪除或保持原樣。 – devuxer 2009-09-01 23:15:23