1. 程式人生 > >C#中的Linq to Xml詳解

C#中的Linq to Xml詳解

image 查詢 學習 ebo ret 遞增 xdoc 裏的 事件


前言

我相信很多從事.NET開發的,在.NET 3.5之前操作XML會比較麻煩,但是在此之後出現了Linq to Xml,而今天的主人公就是Linq to Xml,廢話不多說,直接進入主題。


一、生成Xml

為了能夠在結構有一定的組織,筆者建議大家新建一個控制臺項目,並且新建一個CreateXml類(以下部分都屬於該類中)。

並在其中寫入以下屬性:


代碼如下:


public static String Path

{

get

{

String path = String.Format(“{0}\\test.xml”, Environment.CurrentDirectory);

return path;

}

}

這句代碼很好理解,就是為了下面我們示例的時候可以將xml保存到當前程序的運行路徑下。

(以下的示例中不會包含Main方法中的寫法,因為Main中僅僅只要調用該靜態方法即可。)


1.創建簡單的Xml

首先我們先練練手,創建一個簡單的Xml並保存到一個文件中。

代碼如下:


代碼如下:


/// <summary>

/// 創建簡單的xml並保存

/// </summary>

public static void CreateElement()

{

XDocument xdoc = new XDocument(

new XDeclaration(“1.0”, “utf-8”, “yes”),

new XElement(“root”,

new XElement(“item”, “1”),

new XElement(“item”, “2”)

));

xdoc.Save(Path);

}

很多學習過XML的人可以從結構就能夠猜測出最終的xml的組織,而這也是linq to xml的優點之一。這句代碼首先創建一個xml文檔,並設置該xml的版本為1.0,

采用utf-8編碼,後面的yes表示該xml是獨立的。下面就開始創建每個節點的,首先是Root節點,然後在Root節點中添加兩個Item節點。

最終生成的Xml如下所示:


代碼如下:


<?xml version=”1.0″ encoding=”utf-8″ standalone=”yes”?>

<root>

<item>1</item>

<item>2</item>

</root>


2.創建註釋

當xml有很多項時,我們就需要利用註釋加以區別,通過linq to xml我們一樣可以在其中添加註釋。

比如下面這段代碼:


代碼如下:


/// <summary>

/// 創建註釋

/// </summary>

public static void CreateComment()

{

XDocument doc = new XDocument(

new XDeclaration(“1.0”, “utf-8”, “yes”),

new XComment(“提示”),

new XElement(“item”, “asd”)

);

doc.Save(Path);

}

這裏我們直接在版本信息的後面添加了一條註釋。

最終的結果如下所示:


代碼如下:


<?xml version=”1.0″ encoding=”utf-8″ standalone=”yes”?>

<!–提示–>

<item>asd</item>


3.根據對象創建xml

很多時候我們都會將數組之類的類型轉換成xml以便保存進永久性存儲介質中,所以下面我們也簡單的舉了一個例子,將數組轉換成xml。

代碼如下所示:


代碼如下:


/// <summary>

/// 根據對象創建xml並保存

/// </summary>

public static void CreateElementByObjects()

{

var s = Enumerable.Range(1, 10);

XElement xele = new XElement(

“Root”,

from item in s

select new XElement(“item”, item.ToString())

);

xele.Save(Path);

}

一開始的代碼 var s = Enumerable.Radge(1,10)是從1開始遞增,生成含有10項的數組,以便後面我們進行添加,有了這個數組之後,

我們通過簡單的linq語句將數組轉換成xml,添加到Root中。

保存之後的結果如下:


代碼如下:


<?xml version=”1.0″ encoding=”utf-8″?>

<Root>

<item>1</item>

<item>2</item>

<item>3</item>

<item>4</item>

<item>5</item>

<item>6</item>

<item>7</item>

<item>8</item>

<item>9</item>

<item>10</item>

</Root>


4.創建屬性

有時我們不想創建新的子項去保存數據,而是使用屬性的方式去保存。理所應當,linq to xml一樣也支持這個功能,下面我們可以通過簡單的語句去實現它。

代碼如下所示:


代碼如下:


/// <summary>

/// 創建屬性

/// </summary>

public static void CreteAttribute()

{

XAttribute xa = new XAttribute(“V2”, “2”);

XElement xele = new XElement(

“Root”,

new XElement(“Item”,

new XAttribute(“V1”, “1”),

xa

));

xele.Save(Path);

}

我們依然可以看到熟悉的語法,這裏我們利用了XAttribute去創建一個屬性,並添加到XElement中。

最終的結果如下:


代碼如下:


<?xml version=”1.0″ encoding=”utf-8″?>

<Root>

<Item V1=”1″ V2=”2″ />

</Root>


5.創建命名空間

對於一些企業級的xml格式,會非常的嚴格。特別是在同一個xml中可能會出現重復的項,但是我們又想區分開來,這個時候我們可以利用命名空間將他們分開(跟C#中的命名空間類似。)。

下面是創建命名空間的示例:


代碼如下:


/// <summary>

/// 創建命名空間

/// </summary>

public static void CreateNamespace()

{

XElement xele = new XElement(“{http://www.xamarin-cn.com}Root”,

new XElement(“Item”, “1”),

new XElement(“{http://www.baidu.com}Item”, 2));

xele.Save(Path);

}

結果如下所示:


代碼如下:


<?xml version=”1.0″ encoding=”utf-8″?>

<Root xmlns=”http://www.xamarin-cn.com”>

<Item xmlns=””>1</Item>

<Item xmlns=”http://www.baidu.com”>2</Item>

</Root>

從這個結果中我們可以看到對應的屬性中有了xmlns屬性,並且值就是我們賦給它的命名空間。


二、查詢並修改Xml

Linq to xml不僅僅是創建xml簡單,在查詢,編輯和刪除方面一樣是非常方便的。下面我們就會介紹這些。

首先我們創建一個QueryXml類,並在其中寫入如下的屬性:


代碼如下:


public static String Path

{

get

{

String path = String.Format(“{0}\\test1.xml”, Environment.CurrentDirectory);

return path;

}

}

同時在該路徑下新建一個test1.xml文件,並在其中寫入如下內容:


代碼如下:


<?xml version=”1.0″ encoding=”utf-8″?>

<Root>

<Item v1=”1″ v2=”2″>Item1</Item>

<Item v1=”1″ v2=”2″ >Item2</Item>

</Root>

下面我們就可以正式開始了。


1.通過文件讀取xml

既然我們要對xml查詢就需要讀取對應的xml文件,當然後面會介紹其他的方式。

代碼如下:


代碼如下:


/// <summary>

/// 通過文件讀取xml

/// </summary>

public static void QueryElementByFile()

{

XElement xele = XElement.Load(Path);

XElement xele1 = xele.Element(“Item”);

Console.Write(xele1.Value.Trim());

Console.ReadKey();

}

我們可以利用XElement的靜態方法Load讀取指定路徑下的xml文件,這裏我們不僅讀取了該xml文件,同時還獲取的該xml的第一個item的值並輸出。

所以我們可以看到如下的結果:

技術分享圖片


2.在指定節點前後添加新節點

上面我們僅僅只是讀取xml以及簡單的查詢,下面我們不僅僅查詢並且還要在該節點前後插入新的節點。

代碼如下:


代碼如下:


/// <summary>

/// 在指定節點前後添加新節點

/// </summary>

public static void AddToElementAfterAndBefore()

{

XElement xele = XElement.Load(Path);

var item = (from ele in xele.Elements(“Item”)

where ele.Value.Equals(“Item2”)

select ele).SingleOrDefault();

if (item != null)

{

XElement nele = new XElement(“NItem”, “NItem”);

XElement nele2 = new XElement(“BItem”, “BItem”);

item.AddAfterSelf(nele);

item.AddBeforeSelf(nele2);

xele.Save(Path);

}

}

我們簡單的分析一下上面的代碼,首先我們利用linq從中查詢Item的值為Item2的節點,然後獲取其中第一個節點,然後通過AddAfterSelf和AddBeforeSelf在該節點的後面和前面分別添加新的節點。

添加完之後的xml結果如下:


代碼如下:


<?xml version=”1.0″ encoding=”utf-8″?>

<Root>

<Item v1=”1″ v2=”2″>Item1</Item>

<BItem>BItem</BItem>

<Item v1=”1″ v2=”2″>Item2</Item>

<NItem>NItem</NItem>

</Root>


3.添加屬性到節點中

我們已經可以動態的添加節點,但是創建的時候不僅僅可以創建節點,並且還能創建屬性,下面我們可以通過SetAttributeValue去添加新的屬性或者修改現有屬性。

代碼如下:


代碼如下:


/// <summary>

/// 添加屬性到節點中

/// </summary>

public static void AddAttributeToEle()

{

XElement xele = XElement.Parse(@”<?xml version=’1.0′ encoding=’utf-8′?><Root><!–前面的註釋–>

<Item v1=’1′ v2=’2′>Item1</Item><!–後面的註釋–><Item v1=’1′ v2=’2′ v3=’3′>Item2</Item></Root>”);

var item = (from ele in xele.Elements(“Item”)

where ele.Value.Equals(“Item2”)

select ele).SingleOrDefault();

item.SetAttributeValue(“v3”, “3”);

xele.Save(Path);

}

我們可以明顯的看出,這裏我們已經不是使用XElement.Load去讀取xml文件,而是通過直接讀取xml字符串。接著我們還是跟上面一樣去查詢,然後通過SetAttributeValue添加了新的屬性,並保存。

Xml內容如下:


代碼如下:


<?xml version=”1.0″ encoding=”utf-8″?>

<Root>

<!–前面的註釋–>

<Item v1=”1″ v2=”2″>Item1</Item>

<!–後面的註釋–>

<Item v1=”1″ v2=”2″ v3=”3″>Item2</Item>

</Root>

我們可以看到第二個Item中多了一個 v3=”3” 新的屬性。


4.添加註釋到指定節點前後

這裏的語法基本跟添加節點到指定節點前後是相似的,只是讀取xml的方式不同。

代碼如下:


代碼如下:


/// <summary>

/// 添加註釋到節點前後

/// </summary>

public static void AddCommentToAfterAndBefore()

{

TextReader tr = new StringReader(@”<?xml version=’1.0′ encoding=’utf-8′?><Root><!–前面的註釋–>

<Item v1=’1′ v2=’2′>Item1</Item><!–後面的註釋–><Item v1=’1′ v2=’2′ v3=’3′>Item2</Item></Root>”);

XElement xele = XElement.Load(tr);

var item = (from ele in xele.Elements(“Item”)

where ele.Value.Equals(“Item1”)

select ele).FirstOrDefault();

if (item != null)

{

XComment xcom = new XComment(“後面的註釋”);

XComment xcoma = new XComment(“前面的註釋”);

item.AddAfterSelf(xcom);

item.AddBeforeSelf(xcoma);

}

tr.Close();

xele.Save(Path);

}

上面我使用StringReader和TextReader讀取xml字符串並使用XElement.Load讀取該對象,然後就是在新建節點的時候新建的是註釋節點,最後利用一樣的語法添加到指定節點前後。

最終結果如下:


代碼如下:


<?xml version=”1.0″ encoding=”utf-8″?>

<Root>

<!–前面的註釋–>

<!–前面的註釋–>

<Item v1=”1″ v2=”2″>Item1</Item>

<!–後面的註釋–>

<!–後面的註釋–>

<Item v1=”1″ v2=”2″ v3=”3″>Item2</Item>

</Root>


5.替換指定節點

修改節點的值通過SetValue即可做到,但是有時涉及到子節點,而我們想一次性全部替換掉,那麽我們就需要使用ReplaceWith。

代碼如下:


代碼如下:


/// <summary>

/// 替換指定節點

/// </summary>

public static void ReplaceElement()

{

XElement xele = XElement.Load(Path);

var item = (from ele in xele.Elements(“Item”)

where ele.Value.Equals(“Item2”)

select ele).FirstOrDefault();

if (item != null)

{

item.ReplaceWith(new XElement(“Item”, “Item3”));

}

xele.Save(Path);

}

這裏的重點在於ReplaceWith方法,調用該方法會發生兩個操作。首先是刪除該節點,然後在該節點的位置上將我們的節點插入完成替換。

最後的xml結果如下:


代碼如下:


<?xml version=”1.0″ encoding=”utf-8″?>

<Root>

<!–前面的註釋–>

<!–前面的註釋–>

<Item v1=”1″ v2=”2″>Item1</Item>

<!–後面的註釋–>

<!–後面的註釋–>

<Item>Item3</Item>

</Root>

這樣我們很輕易的就替換了整個節點。


6.刪除指定屬性

前面我們介紹了創建、修改和添加屬性,但是還沒有介紹如何刪除指定的屬性,下面我們就通過一個簡單的實例來演示。

代碼如下:


代碼如下:


/// <summary>

/// 刪除指定屬性

/// </summary>

public static void RemoveAttribute()

{

XElement xele = XElement.Load(Path);

var item = (from ele in xele.Elements(“Item”)

where ele.Value.Equals(“Item1”)

select ele).FirstOrDefault().Attribute(“v1”);

if (item != null)

{

item.Remove();

}

xele.Save(Path);

}

我們首先查詢出指定的節點,然後指定某個屬性,最後調用XAttribute的Remove方法既可。

結果如下:


代碼如下:


<?xml version=”1.0″ encoding=”utf-8″?>

<Root>

<!–前面的註釋–>

<!–前面的註釋–>

<Item v2=”2″>Item1</Item>

<!–後面的註釋–>

<!–後面的註釋–>

<Item>Item3</Item>

</Root>


7.刪除指定節點

既然上面已經可以刪除屬性,自然也少不了刪除屬性。

代碼如下所示:


代碼如下:


/// <summary>

/// 刪除指定節點

/// </summary>

public static void RemoveElement()

{

XElement xele = XElement.Load(Path);

var item = (from ele in xele.Elements(“Item”)

where ele.Value.Equals(“Item1”)

select ele).FirstOrDefault();

if (item != null)

{

item.Remove();

}

xele.Save(Path);

}

依然是調用同樣的方法。

結果如下:


代碼如下:


<?xml version=”1.0″ encoding=”utf-8″?>

<Root>

<!–前面的註釋–>

<!–前面的註釋–>

<!–後面的註釋–>

<!–後面的註釋–>

<Item>Item3</Item>

</Root>


三、按節點關系查詢

上面的查詢都是通過相關的條件進行查詢,但是我們有時僅僅只需要通過之間的關系即可,這樣反而可以避免很多的代碼,當然稍加探索可以發現其實XElement都提供給我們了。

我們依然要新建一個StructureXml類,並在其中新建一個屬性。

如下所示:


代碼如下:


public static String Path

{

get

{

String path = String.Format(“{0}\\test2.xml”, Environment.CurrentDirectory);

return path;

}

}

同時在該文件夾下新建一個test2.xml並寫入如下內容:


代碼如下:


<?xml version=”1.0″ encoding=”utf-8″ ?>

<Root>

<Item>

<SubItem1>

1

</SubItem1>

<SubItem>

<Child>

sss

</Child>

</SubItem>

<SubItem2>

2

</SubItem2>

</Item>

</Root>


1.顯示指定節點的所有父節點

通過上面的xml文件,我們清晰的看出xml是具有結構性的,彼此之間都存在關系,而現在我們需要顯示某個節點的父級節點的名稱。

代碼如下所示:


代碼如下:


/// <summary>

/// 顯示指定節點的所有父節點

/// </summary>

public static void ShowAllParentEle()

{

XElement xele = XElement.Load(Path);

var item = (from ele in xele.Descendants(“Child”)

select ele).FirstOrDefault();

if (item != null)

{

foreach (var sub in item.Ancestors())

{

Console.WriteLine(sub.Name);

}

Console.WriteLine(“—————-“);

foreach (var sub in item.AncestorsAndSelf())

{

Console.WriteLine(sub.Name);

}

Console.ReadKey();

}

}

其中我們通過Descendants獲取最底的節點,然後使用Ancestors獲取所有的父級節點,而AncestorsAndSelf則表示包含本身。

最終結果如下所示:

技術分享圖片

我們從圖中看出,分割線前顯示的是不包含本身的,而下面是包含本身的。


2.顯示指定節點的所有子節點

我們不僅僅可以輸出一個節點的所有父級節點,同樣也可以輸出一個節點的所有子節點。

代碼如下所示:


代碼如下:


/// <summary>

/// 顯示指定節點的所有子節點

/// </summary>

public static void ShowAllChildEle()

{

XElement xele = XElement.Load(Path);

foreach (var sub in xele.Descendants())

{

Console.WriteLine(sub.Name);

}

Console.WriteLine(“—————–“);

foreach (var sub in xele.DescendantsAndSelf())

{

Console.WriteLine(sub.Name);

}

Console.ReadKey();

}

這裏我們依然是分成輸出子級節點以及包含自己的。

結果如下所示:

技術分享圖片


3.顯示同級節點之前的節點

既然有了父子關系,當然也少不了同級關系,首先我們先顯示同級節點之前的節點。

代碼如下所示:


代碼如下:


/// <summary>

/// 顯示同級節點之前的節點

/// </summary>

public static void ShowPrevEle()

{

XElement xele = XElement.Load(Path);

var item = (from ele in xele.Descendants(“SubItem”)

select ele).FirstOrDefault();

if (item != null)

{

foreach (var sub in item.ElementsBeforeSelf())

{

Console.WriteLine(sub.Name);

}

}

Console.ReadKey();

}

這裏我們看到我們通過ElementsBeforeSelf獲取該節點之前的同級節點,當然我們還可以傳入參數作為限制條件。這裏我們通過查詢獲取了SubItem這個節點,並顯示該節點之前的同級節點。

最終結果如下:

技術分享圖片


4.顯示同級節點後面的節點

作為上面的補充。

代碼如下所示:


代碼如下:


/// <summary>

/// 顯示同級節點後面的節點

/// </summary>

public static void ShowNextEle()

{

XElement xele = XElement.Load(Path);

var item = (from ele in xele.Descendants(“SubItem”)

select ele).FirstOrDefault();

if (item != null)

{

foreach (var sub in item.ElementsAfterSelf())

{

Console.WriteLine(sub.Name);

}

}

Console.ReadKey();

}

最終結果如下所示:

技術分享圖片


四、監聽xml事件

你可能會疑惑xml為什麽還要監聽,其實這樣是有意義的,比如你要根據某個節點的值作為依賴,那麽你就要監聽這個節點,如果這個節點發生改變的時候,

你才可以及時的作出反應。但是xml的事件監聽有一個特點,跟瀏覽器中的DOM事件類似,監聽父節點同樣也可以監聽的到它的子節點的事件。下面我們

通過一個簡單的實例來說明。

實例代碼如下:


代碼如下:


public static class EventXml

{

public static void BindChangeing()

{

XElement xele = new XElement(“Root”);

xele.Changing += xele_Changing;

xele.Changed += xele_Changed;

xele.Add(new XElement(“Item”, “123”));

var item = xele.Element(“Item”);

item.ReplaceWith(new XElement(“Item”, “2”));

item = xele.Element(“Item”);

item.Remove();

Console.ReadKey();

}

static void xele_Changed(object sender, XObjectChangeEventArgs e)

{

XElement ele = sender as XElement;

Console.WriteLine(String.Format(“已完成 {0}-{1}”, ele.Name, e.ObjectChange));

}

static void xele_Changing(object sender, XObjectChangeEventArgs e)

{

XElement ele = sender as XElement;

Console.WriteLine(String.Format(“正在進行中 {0}-{1}”, ele.Name, e.ObjectChange));

}

}

除聲明外,跑步客文章均為原創,轉載請以鏈接形式標明本文地址
C#中的Linq to Xml詳解

本文地址: http://www.paobuke.com/develop/c-develop/pbk23152.html






相關內容

技術分享圖片c#檢測文本文件編碼的方法技術分享圖片C#獲取CPU編號的方法技術分享圖片C#求n個數中最大值和最小值的方法技術分享圖片C#中數組初始化與數組元素復制的方法
技術分享圖片C#操作PowerPoint的方法技術分享圖片C#實現根據給出的相對地址獲取網站絕對地址的方法技術分享圖片C# IDE VS2005中的Hosting Process (vshost.exe)作用介紹技術分享圖片C#實現鼠標移動到曲線圖上顯示值的方法

C#中的Linq to Xml詳解