與Value打交道
XElement與XAttribute的都有一個string類型的Value屬性. 如果一個元素包含有一個單一的XText子節點, 那麼XElement的Value屬性就相當於訪問此節點內容的快捷方式. 對於XAttribute, Value屬性就是指attribute的值.
盡管存儲體不一樣, X-DOM還是提供了一致的操作方式用於元素和attribute的值.
設置Values
有兩中方式用於分配一個值: 調用SetValue或者賦值給Value屬性. 相比之下SetValue更加靈活一點, 因為它不僅僅接受string類型, 也可以接受其他的簡單類型:
1: var e = new XElement ("date", DateTime.Now);
2: e.SetValue (DateTime.Now.AddDays(1));
3: Console.Write (e.Value);
我們可以簡單的設置值到元素的Value屬性, 但這意味著你需要手動將DateTime轉換成string類型. 這將會更加復雜–因為它需要使用XmlConvert來轉換成為一個XML兼容的結果.
獲取Values
為了將一個Value值轉換成為其基礎類型, 我們可以簡單轉換XElement或者XAttribute到我們期望的類型. 這聽起來似乎是不能工作的, 但實際上是它完全沒有任何問題. 例如:
1: XElement e = new XElement ("now", DateTime.Now);
2: DateTime dt = (DateTime) e;
3:
4: XAttribute a = new XAttribute ("resolution", 1.234);
5: double res = (double) a;
一個元素或者attribute並不會天然的存儲DateTime或者數字–他們總是將其保存為文本, 然後轉換為真正需要的. 它也沒有記住其原始類型, 因為你必須要將其轉換為正確的類型以避免出現運行時錯誤.要讓你的代碼更加健壯, 可以使用try / catch塊, 捕獲一個FormatException.
XElement與XAttribute的顯式轉換可以將其轉換為以下的類型:
如果請求的名稱不存在的時候, 轉換到nullable類型在對於連帶著Element和Attribute的方法是非常有用的, 其轉換應該可以順利完成. 例如, 如果x沒有timeout元素, 第一行將會引起一個運行時錯誤, 而第二行則不會:
1: int timeout = (int) x.Element ("timeout"); // 錯誤
2: int? timeout = (int?) x.Element ("timeout"); // OK
我們可以使用??操作符來去除最後結果中的nullable類型. 以下的代碼在resolution屬性不存在的情況下將會返回1.0
1: double resolution =
2: (double?) x.Attribute ("resolution") ?? 1.0;
不過, 如果element或者attribute存在並且包含一個空值(或者不正確的格式), 轉換到nullable類型並不會讓你就遠離麻煩. 上述情況, 你將會得到一個FormatException.
我們也可以在LINQ查詢中使用類型轉換. 例如以下的查詢返回”John”:
1: var data = XElement.Parse (
2: @"<data>
3: <customer id='1' name='Mary' credit='100' />
4: <customer id='2' name='John' credit='150' />
5: <customer id='3' name='Anne' />
6: </data>");
7:
8: IEnumerable<string> query =
9: from cust in data.Elements( )
10: where (int?) cust.Attribute ("credit") > 100
11: select cust.Attribute ("name").Value;
轉換到一個nullable的int類型避免了NullReferenceException的產生(Anne沒有credit屬性). 另一種解決方案是給加一個斷言到where從句中.
1: where cust.Attributes ("credit").Any()
2: &&(int) cust.Attribute...
同樣的原則也可以應用於查詢元素的值.
值與混合的內容節點
由於有了Value屬性, 你可能會好奇什麼時候你才需要直接和XText節點打交道呢? 答案是: 當你擁有混合的內容的時候. 例如:
1: <summary>
2: An XAttribute is <bold>not</bold> an XNode
3: </summary>
一個簡單的Value屬性是不能夠獲取summary的全部內容的. summary元素包含了3個孩子:一個XText節點, 緊接著一個XElement, 然後再一個XText節點. 我們來看它是如何被構造的:
1: XElement summary = new XElement ("summary",
2: new XText ("An XAttribute is "),
3: new XElement ("bold", "not"),
4: new XText (" an XNode")
5: );
有趣的是, 你依然還是可以查詢summary的Value值, 這並不會引起任何的異常. 相反, 我們獲得了每一個子節點的Value值的連接字符.
An XAttribute is not an XNode
重設summary的Value值也是合法的, 它將使用一個單一的XText節點替換前面提到的所子節點.
自動XText連接
當你增加簡單內容到一個XElement的時候, X-DOM將其添加到已存在的XText子節點中而不是去創建一個新的節點. 在下面的例子中, e1和e2最後形成了一個單一的XText元素, 其值是”HelloWorld”.
1: var e1 = new XElement ("test", "Hello");
2: e1.Add ("World");
3:
4: var e2 = new XElement ("test", "Hello", "World");
如果你指定要創建XText節點, 最終將會形成多個孩子節點:
1: var e = new XElement ("test",
2: new XText ("Hello"),
3: new XText ("World"));
4: Console.WriteLine (e.Value); // HelloWorld
5: Console.WriteLine (e.Nodes( ).Count( )); // 2
XElement不會自動連接兩個XText節點, 因此它們的對象身份是被保持的. 待續!