LINQ To XML : Descendants函式

摘要:LINQ To XML : Descendants函式

LINQ To XML : Descendants函式
 
    在LINQ To XML 的架構中,若想取得某個Element下的指定之子Element,可以呼叫Descendants這個Extension Method,如下所示:
foreach (XElement elem in doc.Elements("Customers").Descendants("Customer"))
      Console.WriteLine(string.Format("Customer ID : {0}, Name : {1}, Address : {2}",
                                                elem.Attribute("ID").Value,
                                                elem.Attribute("Name").Value,
                                                elem.Attribute("Address").Value));
此例所使用的XML如下:
<?xml version="1.0" encoding="utf-8"?>
<Customers>
 <Customer ID="A0001" Name="Tom" Address="Taipen" />
 <Customer ID="A0002" Name="Mary" Address="LD" />
 <Customer ID="A0003" Name="Jeff" Address="YW" />
</Customers>
不過,這有個特別的情況,當XML中包含了Namespace時,傳入Descendants的指定Element名稱就必須包含Namespace,舉個例來說,下面的.dbml(LINQ To SQL的定義檔)。
<?xmlversion="1.0"encoding="utf-8"?>
<DatabaseName="Northwind"Class="DataClasses1DataContext"
        xmlns="http://schemas.microsoft.com/linqtosql/dbml/2007">
 <ConnectionMode="AppSettings"ConnectionString=
"Data Source=JEFFRAY;Initial Catalog=Northwind;Integrated Security=True"SettingsObjectName="LTSync.Properties.Settings"SettingsPropertyName="NorthwindConnectionString"Provider="System.Data.SqlClient" />
...........
 </Database>
如果用下面的程式來列舉Connection Element,會以失敗收場。
var cstr = (from s1 in doc.Descendants("Connection") select s1).First();
問題的徵結點在於.dbml中定義了Namespace,而我們於呼叫 Descendants時,只傳入Element的LocalName部份所致,仔細查看Descendants函式的宣告,你會發現其事實上接收的是一 個XName型別的物件,由於XName實作了隱含轉型運算子,所以很自然的將我們傳入的字串隱含轉型為XName,只是此時得到的XName物件中只包 含了LocalName部份,並未包含Namespace部份。
要順利取得Connection Element,我們可以用下面的程式碼來達成。
var cstr = (from s1 in doc.Descendants() where s1.Name.LocalName == "Connection" select s1).First();
此例中我們以未帶參數的Descendants函式來取得所有子Element,並一一比對其LocalName,忽略掉Namespace。
另一個手法是直接以Root Element的Namespace來疊加LocalName,如下所示:
var cstr = (from s1 in doc.Descendants(doc.Root.Name.Namespace+"Connection") select s1).First();
此手法的缺點是,欲取得的Element之Namespace必須與Root Element相同。