一、LINQ to XML 編程基礎(chǔ)
1、LINQ to XML類
System.Xml.Linq命名空間含有19個(gè)類,下表列出了它們的名稱及其描述:
類 |
描述 |
XAttribute |
表示一個(gè) XML 屬性 |
XCData |
表示一個(gè) CDATA 文本節(jié)點(diǎn) |
XComment |
表示一個(gè) XML 注釋 |
XContainer |
適用于可能具有子節(jié)點(diǎn)的所有節(jié)點(diǎn)的抽象基類 |
XDeclaration |
表示一個(gè) XML 聲明 |
XDocument |
表示一個(gè) XML 文檔 |
XDocumentType |
表示一個(gè) XML 文檔類型定義 (DTD) |
XElement |
表示一個(gè) XML 元素 |
XName |
表示一個(gè)XML元素或?qū)傩缘拿Q |
XNamespace |
表示一個(gè)XML的命名空間 |
XNode |
一個(gè)抽象類,它表示 XML 樹(shù)的節(jié)點(diǎn) |
XNodeDocumentOrderComparer |
提供用于比較節(jié)點(diǎn)的文檔順序的功能 |
XNodeEqualityComparer |
提供用于比較節(jié)點(diǎn)的值是否相等的功能 |
XObject |
XNode 和 XAttribute 的抽象基類 |
XObjectChange |
XObject引發(fā)事件時(shí)的事件類型 |
XObjectChangeEventArgs |
為 Changing 和 Changed 事件提供數(shù)據(jù) |
XProcessingInstruction |
表示一個(gè) XML 處理指令 |
XText |
表示一個(gè)文本節(jié)點(diǎn) |
以下的代碼演示了如何使用LINQ to XML來(lái)快速創(chuàng)建一個(gè)xml:
復(fù)制代碼代碼如下:
public static void CreateDocument()
{
XDocument xdoc = new XDocument
(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("Root","root")
);
xdoc.Save(path);
}
運(yùn)行該示例將會(huì)得到一個(gè)xml文件,其內(nèi)容為:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Root>root</Root>
可以看出微軟在LINQ上投入了很大的精力,使我們?cè)诰幊虝r(shí)感覺(jué)到很舒服。下面將詳細(xì)介紹處理XML時(shí)使用最多的三個(gè)類:XElement、XAttribute和XDocument。如果掌握了這些類,使用LINQ to XML時(shí)將會(huì)感到很順手。
2、XElement類
XElement 類是 LINQ to XML 中的基礎(chǔ)類之一。 它表示一個(gè) XML 元素。 可以使用該類創(chuàng)建元素;更改元素內(nèi)容;添加、更改或刪除子元素;向元素中添加屬性;或以文本格式序列化元素內(nèi)容。 還可以與 System.Xml 中的其他類(例如 XmlReader、XmlWriter 和 XslCompiledTransform)進(jìn)行互操作。
使用LINQ to XML創(chuàng)建xml文檔有很多種方式,具體使用哪種方法要根據(jù)實(shí)際需要。而創(chuàng)建xml文檔最簡(jiǎn)單、最常見(jiàn)的方式是使用XElement類。以下的代碼演示了如何使用XElement類創(chuàng)建一個(gè)xml文檔:
復(fù)制代碼代碼如下:
public static void CreateCategories()
{
XElement root = new XElement("Categories",
new XElement("Category",
new XElement("CategoryID", Guid.NewGuid()),
new XElement("CategoryName", "Beverages")
),
new XElement("Category",
new XElement("CategoryID", Guid.NewGuid()),
new XElement("CategoryName", "Condiments")
),
new XElement("Category",
new XElement("CategoryID", Guid.NewGuid()),
new XElement("CategoryName", "Confections")
)
);
root.Save(path);
}
運(yùn)行該示例將會(huì)得到一個(gè)xml文件,其內(nèi)容為:
復(fù)制代碼代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<Categories>
<Category>
<CategoryID>57485174-46fc-4e8c-8d98-d25b53d504a1</CategoryID>
<CategoryName>Beverages</CategoryName>
</Category>
<Category>
<CategoryID>1474dde1-8014-48f7-b093-b47ca5d5b770</CategoryID>
<CategoryName>Condiments</CategoryName>
</Category>
<Category>
<CategoryID>364224e0-e002-4939-90fc-0fd93e0cf35b</CategoryID>
<CategoryName>Confections</CategoryName>
</Category>
</Categories>
LINQ to XML的強(qiáng)大之處還在于它可以使用LINQ to SQL或者LINQ to Object獲取數(shù)據(jù)源,然后填充到xml樹(shù)。以下的示例從Northwind數(shù)據(jù)庫(kù)中讀取Categories、Products表中的數(shù)據(jù)來(lái)創(chuàng)建包含產(chǎn)品類別,以及每個(gè)類別下所有產(chǎn)品的xml文件:
復(fù)制代碼代碼如下:
public static void CreateCategoriesFromDatabase()
{
using (NorthwindDataContext db = new NorthwindDataContext())
{
XElement root = new XElement("Categories",
db.Categories
.Select
(
c => new XElement
(
"Category"
, new XElement("CategoryID", c.CategoryID)
, new XElement("CategoryName", c.CategoryName)
, new XElement
(
"Products"
, c.Products
.Select
(
p => new XElement
(
"Product"
, new XElement("ProductName", p.ProductName)
)
)
.Take(2)
)
)
)
.Take(3)
);
root.Save(path);
}
}
運(yùn)行該示例將會(huì)得到一個(gè)xml文件,其內(nèi)容為:
復(fù)制代碼代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<Categories>
<Category>
<CategoryID>1</CategoryID>
<CategoryName>Beverages</CategoryName>
<Products>
<Product>
<ProductName>Chai</ProductName>
</Product>
<Product>
<ProductName>Chang</ProductName>
</Product>
</Products>
</Category>
<Category>
<CategoryID>2</CategoryID>
<CategoryName>Condiments</CategoryName>
<Products>
<Product>
<ProductName>Aniseed Syrup</ProductName>
</Product>
<Product>
<ProductName>Chef Anton's Cajun Seasoning</ProductName>
</Product>
</Products>
</Category>
<Category>
<CategoryID>3</CategoryID>
<CategoryName>Confections</CategoryName>
<Products>
<Product>
<ProductName>Pavlova</ProductName>
</Product>
<Product>
<ProductName>Teatime Chocolate Biscuits</ProductName>
</Product>
</Products>
</Category>
</Categories>
XElement類包含了許多方法,這些方法使得處理xml變得輕而易舉。有關(guān)這些方法請(qǐng)參照MSDN。
其中,Save、CreateReader、ToString和WriteTo方法是比較常用的三個(gè)方法:
方法 |
參數(shù) |
返回值 |
描述 |
CreateReader |
無(wú) |
System.Xml.XmlReader |
創(chuàng)建此節(jié)點(diǎn)的 XmlReader |
Save |
System.String |
void |
將此元素序列化為文件 |
System.IO.TextWriter |
void |
將此元素序列化為 TextWriter |
|
System.Xml.XmlWriter |
void |
將此元素序列化為 XmlWriter |
|
System.String, System.Xml.Linq.SaveOptions |
void |
將此元素序列化為文件,并可以選擇禁用格式設(shè)置 |
|
System.IO.TextWriter, System.Xml.Linq.SaveOptions |
void |
將此元素序列化為 TextWriter,并可以選擇禁用格式設(shè)置 |
|
WriteTo |
System.Xml.XmlWriter |
void |
將此元素寫(xiě)入 XmlWriter |
ToString |
無(wú) |
System.String |
返回此節(jié)點(diǎn)的縮進(jìn) XML |
System.Xml.Linq.SaveOptions |
System.String |
返回此節(jié)點(diǎn)的 XML,并可以選擇禁用格式設(shè)置 |
現(xiàn)在有很多使用XmlReader作為數(shù)據(jù)源的應(yīng)用程序,使用XElement可以很方便地提供支持。
3、XAttribute類
XAttribute類用來(lái)處理元素的屬性,屬性是與元素相關(guān)聯(lián)的“名稱-值”對(duì),每個(gè)元素中不能有名稱重復(fù)的屬性。使用XAttribute類與使用XElement類的操作十分相似,下面的示例演示了如何在創(chuàng)建xml樹(shù)時(shí)為其添加一個(gè)屬性:
復(fù)制代碼代碼如下:
public static XElement CreateCategoriesByXAttribute()
{
XElement root = new XElement("Categories",
new XElement("Category",
new XAttribute("CategoryID", Guid.NewGuid()),
new XElement("CategoryName", "Beverages")
),
new XElement("Category",
new XAttribute("CategoryID", Guid.NewGuid()),
new XElement("CategoryName", "Condiments")
),
new XElement("Category",
new XAttribute("CategoryID", Guid.NewGuid()),
new XElement("CategoryName", "Confections")
)
);
root.Save(path);
return root;
}
運(yùn)行該示例將會(huì)得到一個(gè)xml文件,其內(nèi)容為:
復(fù)制代碼代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<Categories>
<Category CategoryID="a6d5ef04-3f83-4e00-aeaf-52444add7570">
<CategoryName>Beverages</CategoryName>
</Category>
<Category CategoryID="67a168d5-6b22-4d82-9bd4-67bec88c2ccb">
<CategoryName>Condiments</CategoryName>
</Category>
<Category CategoryID="17398f4e-5ef1-48da-8a72-1c54371b8e76">
<CategoryName>Confections</CategoryName>
</Category>
</Categories>
XAttribute類的方法比較少,常用的三個(gè)是:
方法 |
描述 |
AddAnnotation |
為該屬性添加注解 |
Remove |
刪除該屬性 |
SetValue |
設(shè)定該屬性的值 |
以下的示例使用Remove來(lái)刪除第一個(gè)元素的CategoryID屬性:
復(fù)制代碼代碼如下:
public static void RemoveAttribute()
{
XElement xdoc = CreateCategoriesByXAttribute();
XAttribute xattr = xdoc.Element("Category").Attribute("CategoryID");
xattr.Remove();
xdoc.Save(path);
}
運(yùn)行該示例將會(huì)得到一個(gè)xml文件,其內(nèi)容為:
復(fù)制代碼代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<Categories>
<Category>
<CategoryName>Beverages</CategoryName>
</Category>
<Category CategoryID="5c311c1e-ede5-41e5-93f7-5d8b1d7a0346">
<CategoryName>Condiments</CategoryName>
</Category>
<Category CategoryID="bfde8db5-df84-4415-b297-cd04d8db9712">
<CategoryName>Confections</CategoryName>
</Category>
</Categories>
作為嘗試,試一試以下刪除屬性的方法:
復(fù)制代碼代碼如下:
public static void RemoveAttributeByDoc()
{
XElement xdoc = CreateCategoriesByXAttribute();
XAttribute xattr = xdoc.Attribute("CategoryID");
xattr.Remove();
xdoc.Save(path);
}
運(yùn)行該示例將會(huì)拋出一個(gè)空引用異常,因?yàn)樵谻ategories沒(méi)有一個(gè)叫做CategoryID的屬性。
4、XDocument類
XDocument類提供了處理xml文檔的方法,包括聲明、注釋和處理指令。一個(gè)XDocument對(duì)象可以包含以下內(nèi)容:
對(duì)象 |
個(gè)數(shù) |
說(shuō)明 |
XDeclaration |
一個(gè) |
用于指定xml聲明中的重要組成部分,如文檔編碼和版本等 |
XElement |
一個(gè) |
指定文檔的根元素 |
XDocumentType |
一個(gè) |
表示一個(gè)xml DTD |
XComment |
多個(gè) |
Xml注釋。它不能是第一個(gè)參數(shù),因?yàn)橐粋€(gè)有效的xml文檔不能以注釋作為開(kāi)始 |
XProcessingInstruction |
多個(gè) |
為處理xml的應(yīng)用程序指定任何所需信息 |
下面的示例創(chuàng)建了一個(gè)簡(jiǎn)單的xml文檔,它包含幾個(gè)元素和一個(gè)屬性,以及一個(gè)處理指令和一些注釋:
復(fù)制代碼代碼如下:
public static void CreateXDocument()
{
XDocument xdoc = new XDocument(
new XProcessingInstruction("xml-stylesheet", "title='EmpInfo'"),
new XComment("some comments"),
new XElement("Root",
new XElement("Employees",
new XElement("Employee",
new XAttribute("id", "1"),
new XElement("Name", "Scott Klein"),
new XElement("Title", "Geek"),
new XElement("HireDate", "02/05/2007"),
new XElement("Gender", "M")
)
)
),
new XComment("more comments")
);
xdoc.Save(path);
}
運(yùn)行該示例將會(huì)得到一個(gè)xml文件,其內(nèi)容為:
復(fù)制代碼代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet />
XDocument類包含多個(gè)與XElement類相同的方法,具體內(nèi)容可以參閱MSDN。需要注意的是,處理節(jié)點(diǎn)和元素的大部分功能都可以通過(guò)XElement獲得,只有當(dāng)絕對(duì)需要文檔層次的處理能力,以及需要訪問(wèn)注釋、處理指令和聲明時(shí),才有使用XDocument類的必要。
創(chuàng)建了xml文檔后,可以使用NodesAfterSelf方法返回指定的XElement元素之后的所有同級(jí)元素。需要注意的是,此方法只包括返回集合中的同級(jí)元素,而不包括子代。此方法使用延遲執(zhí)行。以下代碼演示了這一過(guò)程:
復(fù)制代碼代碼如下:
public static void NodesAfterSelf()
{
XElement root = new XElement("Categories",
new XElement("Category",
new XElement("CategoryID", Guid.NewGuid()),
new XElement("CategoryName", "食品"),
new XElement("Description", "可以吃的東西")
)
);
foreach (var item in root.Element("Category").Element("CategoryID").NodesAfterSelf())
{
Console.WriteLine((item as XElement).Value);
}
}
執(zhí)行的結(jié)果如下:
使用LINQ to XML中的類來(lái)處理xml十分簡(jiǎn)單和高效,包括創(chuàng)建、查詢和操縱xml。
二、LINQ to XML編程概念
本節(jié)將介紹LINQ to XML編程的相關(guān)概念,例如如何加載xml、創(chuàng)建全新xml、操縱xml的信息以及遍歷xml文檔。
1、加載已有的xml
使用LINQ to XML加載xml可以從多種數(shù)據(jù)源獲得,例如字符串、XmlReader、TextReader或文件。
下面的示例演示了如何從文件中加載xml:
復(fù)制代碼代碼如下:
public static void LoadFromFile()
{
XElement root = XElement.Load(path);
Console.WriteLine(root.ToString());
}
也可以使用Parse方法從一個(gè)字符串加載xml:
復(fù)制代碼代碼如下:
public static void LoadFromString()
{
XElement root = XElement.Parse(@"
<Categories>
<Category>
<CategoryID>1</CategoryID>
<CategoryName>Beverages</CategoryName>
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
</Category>
</Categories>
");
Console.WriteLine(root.ToString());
}
2、保存xml
在前面的示例中曾多次調(diào)用XElement對(duì)象的Save方法來(lái)保存xml文檔,在這里就不冗述了。
3、創(chuàng)建xml
在前面的示例中曾多次調(diào)用XElement對(duì)象的構(gòu)造函數(shù)來(lái)創(chuàng)建xml文檔,在這里就不冗述了。需要說(shuō)明的是,在使用LINQ to XML創(chuàng)建xml文檔時(shí),會(huì)有代碼縮進(jìn),這使代碼的可讀性大大加強(qiáng)。
4、遍歷xml
使用LINQ to XML在xml樹(shù)中遍歷xml是相當(dāng)簡(jiǎn)單的。只需要使用XElement和XAttribute類中所提供的方法。Elements和Element方法提供了定位到某個(gè)或某些元素的方式。下面的示例演示了如何遍歷xml樹(shù),并獲取指定元素的方式:
復(fù)制代碼代碼如下:
public static void Enum()
{
XElement root = new XElement("Categories");
using (NorthwindDataContext db = new NorthwindDataContext())
{
root.Add(
db.Categories
.Select
(
c => new XElement
(
"Category"
, new XElement("CategoryName", c.CategoryName)
)
)
);
}
foreach (var item in root.Elements("Category"))
{
Console.WriteLine(item.Element("CategoryName").Value);
}
}
}
上述代碼運(yùn)行的結(jié)果為:
是不是很簡(jiǎn)單呢?Nodes()、Elements()、Element(name)和Elements(name)方法為xml樹(shù)的導(dǎo)航提供了基本功能。
5、操縱xml
LINQ to XML一個(gè)重要的特性是能夠方便地修改xml樹(shù),如添加、刪除、更新和復(fù)制xml文檔的內(nèi)容。
I.插入
使用XNode類的插入方法可以方便地向xml樹(shù)添加內(nèi)容:
方法 |
說(shuō)明 |
AddAfterSelf |
緊跟在此節(jié)點(diǎn)之后添加指定的內(nèi)容 |
AddBeforeSelf |
緊鄰此節(jié)點(diǎn)之前添加指定的內(nèi)容 |
在下面的示例中,使用AddAfterSelf方法向現(xiàn)有xml中添加一個(gè)新節(jié)點(diǎn):
復(fù)制代碼代碼如下:
public static void AddAfterSelf()
{
XElement root = XElement.Parse(@"
<Categories>
<Category>
<CategoryID>1</CategoryID>
<CategoryName>Beverages</CategoryName>
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
</Category>
</Categories>
");
XElement xele = root.Element("Category").Element("CategoryName");
xele.AddAfterSelf(new XElement("AddDate", DateTime.Now));
root.Save(path);
}
運(yùn)行該示例將會(huì)得到一個(gè)xml文件,其內(nèi)容為:
復(fù)制代碼代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<Categories>
<Category>
<CategoryID>1</CategoryID>
<CategoryName>Beverages</CategoryName>
<AddDate>2010-01-31T03:08:51.813736+08:00</AddDate>
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
</Category>
</Categories>
當(dāng)需要添加一個(gè)元素到指定節(jié)點(diǎn)之前時(shí),可以使用AddBeforeSelf方法。
II.更新
在LINQ to XML中更新xml內(nèi)容可以使用以下幾種方法:
方法 |
說(shuō)明 |
ReplaceWith |
用指定的內(nèi)容來(lái)取代當(dāng)前元素的內(nèi)容 |
ReplaceAll |
用指定的內(nèi)容來(lái)取代當(dāng)前元素的子節(jié)點(diǎn)及相關(guān)的屬性 |
ReplaceNodes |
用指定的內(nèi)容來(lái)取代文檔或當(dāng)前元素的子節(jié)點(diǎn) |
SetAttributeValue |
設(shè)置屬性的值、添加屬性或移除屬性 |
SetElementValue |
設(shè)置子元素的值、添加子元素或移除子元素 |
在下面的示例中使用了ReplaceWith與SetElementValue方法對(duì)xml進(jìn)行了更新操作:
復(fù)制代碼代碼如下:
public static void Update()
{
XElement root = XElement.Parse(@"
<Categories>
<Category>
<CategoryID>1</CategoryID>
<CategoryName>Beverages</CategoryName>
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
</Category>
</Categories>
");
root.Element("Category").Element("CategoryID").ReplaceWith(new XElement("ID", "2"));
root.Element("Category").SetElementValue("CategoryName", "test data");
root.Save(path);
}
運(yùn)行該示例將會(huì)得到一個(gè)xml文件,其內(nèi)容為:
復(fù)制代碼代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<Categories>
<Category>
<ID>2</ID>
<CategoryName>test data</CategoryName>
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
</Category>
</Categories>
III.刪除
可以使用Remove(XElement)與RemoveAll方法來(lái)刪除xml。
在下面的示例中,使用了RemoveAll方法:
復(fù)制代碼代碼如下:
public static void Remove()
{
XElement root = XElement.Parse(@"
<Categories>
<Category>
<CategoryID>1</CategoryID>
<CategoryName>Beverages</CategoryName>
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
</Category>
</Categories>
");
root.RemoveAll();
root.Save(path);
}
運(yùn)行該示例將會(huì)得到一個(gè)xml文件,其內(nèi)容為:
<?xml version="1.0" encoding="utf-8"?>
<Categories />
在下面的示例中,使用了Remove方法刪除了xml的Description元素:
復(fù)制代碼代碼如下:
public static void Remove()
{
XElement root = XElement.Parse(@"
<Categories>
<Category>
<CategoryID>1</CategoryID>
<CategoryName>Beverages</CategoryName>
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
</Category>
</Categories>
");
root.Element("Category").Element("Description").Remove();
root.Save(path);
}
運(yùn)行該示例將會(huì)得到一個(gè)xml文件,其內(nèi)容為:
復(fù)制代碼代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<Categories>
<Category>
<CategoryID>1</CategoryID>
<CategoryName>Beverages</CategoryName>
</Category>
</Categories>
6、處理屬性
I.添加
LINQ to XML添加屬性與添加元素師類似的,可以使用構(gòu)造函數(shù)或者Add方法來(lái)添加屬性:
復(fù)制代碼代碼如下:
public static void AddAttribute()
{
XElement root = new XElement("Categories",
new XElement("Category",
new XAttribute("CategoryID","1"),
new XElement("CategoryName","Beverages"),
new XElement("Description", "Soft drinks, coffees, teas, beers, and ales")
)
);
root.Element("Category").Add(new XAttribute("AddDate", DateTime.Now.ToShortDateString()));
root.Save(path);
}
運(yùn)行該示例將會(huì)得到一個(gè)xml文件,其內(nèi)容為:
復(fù)制代碼代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<Categories>
<Category CategoryID="1" AddDate="2010-01-31">
<CategoryName>Beverages</CategoryName>
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
</Category>
</Categories>
II.檢索
檢索屬性可以使用Attribute(name)方法:
復(fù)制代碼代碼如下:
public static void SelectAttribute()
{
XElement root = new XElement("Categories",
new XElement("Category",
new XAttribute("CategoryID", "1"),
new XElement("CategoryName", "Beverages"),
new XElement("Description", "Soft drinks, coffees, teas, beers, and ales")
)
);
XAttribute xattr = root.Element("Category").Attribute("CategoryID");
Console.WriteLine(xattr.Name);
Console.WriteLine(xattr.Value);
}
上述代碼的運(yùn)行結(jié)果為:
CategoryID
1
III.刪除
刪除屬性的操作是調(diào)用XAttribute對(duì)象的Remove方法來(lái)完成的。
本文總結(jié)
本文介紹了LINQ to XML的編程基礎(chǔ),即System.Xml.Linq命名空間中的多個(gè)LINQ to XML類,這些類都是LINQ to XML的支持類,它們使得處理xml比使用其他的xml工具容易得多。在本文中,著重介紹的是XElement、XAttribute和XDocument。