C#使用linq to xml完成對XML檔案的建立、增加、删除、修改、查詢
1、XML基本概述
XML檔案是一種常用的檔案格式,例如WinForm裡面的app.config以及Web程式中的web.config檔案,還有許多重要的場所都有它的身影。Xml是Internet環境中跨平台的,依賴于内容的技術,是目前處理結構化文檔資訊的有力工具。XML是一種簡單的資料存儲語言,使用一系列簡單的标記描述資料,而這些标記可以用友善的方式建立,雖然XML占用的空間比二進制資料要占用更多的空間,但XML極其簡單易于掌握和使用。微軟也提供了一系列類庫來倒幫助我們在應用程式中存儲XML檔案。
“在程式中通路進而操作XML檔案一般有兩種模型,分别是使用DOM(文檔對象模型)和流模型,使用DOM的好處在于它允許編輯和更新XML文檔,可以随機通路文檔中的資料,可以使用XPath查詢,但是,DOM的缺點在于它需要一次性的加載整個文檔到記憶體中,對于大型的文檔,這會造成資源問題。流模型很好的解決了這個問題,因為它對XML檔案的通路采用的是流的概念,也就是說,任何時候在記憶體中隻有目前節點,但它也有它的不足,它是隻讀的,僅向前的,不能在文檔中執行向後導航操作。
三種常用的讀取XML檔案的方法。分别是
①使用XmlDocument
②使用XmlTextReader
③使用Linq to Xml
本文主要讨論使用Linq to Xml的方法實作對XML文檔的建立、增加、删除、修改、查詢的操作。
例1:建立XML檔案
string path = "1.xml";
static void Main(string[] args)
{
CreateXml();//建立xml檔案
}
private static void CreateXml()
XDocument xdoc = new XDocument();//建立XDocument對象執行個體
XElement root = new XElement("school");//建立根節點
XElement cls = new XElement("class");//建立class節點
cls.SetAttributeValue("number", "0302");
XElement stu1 = new XElement("student");
stu1.SetAttributeValue("id", "001");
stu1.SetElementValue("name", "張三"); //添加子節點stu1的資料,如姓名張三
stu1.SetElementValue("gender", "男"); //添加子節點stu1的資料,如性别男
stu1.SetElementValue("age", "19"); //添加子節點stu1的資料,如年齡19
//建立子節點class的子節點學生stu2
XElement stu2 = new XElement("student");
stu2.SetAttributeValue("id", "002"); //添加子節點stu2的屬性,如學号002
stu2.SetElementValue("name", "李曉梅"); //添加子節點stu2的資料,如姓名李曉梅
stu2.SetElementValue("gender", "女"); //添加子節點stu2的資料,如性别女
stu2.SetElementValue("age", "18"); //添加子節點stu2的資料,如年齡18
cls.Add(stu1); //添加student到class
cls.Add(stu2); //添加student到class
root.Add(cls); //添加子節點class到根節點school
xdoc.Add(root); //添加根節點到XDoucment對象
xdoc.Save("1.xml"); //使用XML的儲存會自動在xml檔案開始添加:<?xml version="1.0" encoding="utf-8"?>
Console.WriteLine("建立XML檔案成功!");
Console.ReadKey();
檔案内容:
<?xml version="1.0" encoding="utf-8"?>
<school>
<class number="0302">
<student id="001">
<name>張三</name>
<gender>男</gender>
<age>19</age>
</student>
<student id="002">
<name>李曉梅</name>
<gender>女</gender>
<age>18</age>
</class>
</school>
例2:讀取XML檔案
static string path = "1.xml";
// CreateXml();//建立xml檔案
ReadXml();
private static void ReadXml()
XDocument xdoc = XDocument.Load(path);//加載XML檔案
XElement rootSchool = xdoc.Root;//擷取根節點
IEnumerable<XElement> xeles = rootSchool.Elements();
foreach (XElement xeleClass in xeles)
{
foreach (XElement xeleStudent in xeleClass.Elements())
{
Console.WriteLine(xeleStudent.Name); //擷取節點名
Console.WriteLine(xeleStudent.Attribute("id").Value); //擷取屬性值
Console.WriteLine(xeleStudent.Element("name").Value); //下面3行是擷取資料
Console.WriteLine(xeleStudent.Element("gender").Value);
Console.WriteLine(xeleStudent.Element("age").Value);
}
}
例3:增加資料
private static void AddData()
XDocument xdoc = XDocument.Load(path);
XElement xeleRoot = xdoc.Root;
//在已存在的節點上添加屬性和資料
XElement xeleClass = xeleRoot.Element("class");
XElement xeleStu3 = new XElement("student");
xeleStu3.SetAttributeValue("id", "005");
xeleStu3.SetElementValue("name", "王五");
xeleStu3.SetElementValue("gender", "男");
xeleStu3.SetElementValue("age", "40");
xeleClass.Add(xeleStu3);
xdoc.Save("1.xml");
Console.WriteLine("添加xml成功");
運作結果:
例4:删除資料
private static void DeleteData()
XDocument xdoc = XDocument.Load("1.xml");
//删除根節點的直接子節點
XElement xeleClass = xeleRoot.Elements("class").Where(x => x.Attribute("number").Value == "0302").Single(); //拉姆達表達式
xeleClass.Remove();
//删除根節點的直接子節點的下一級節點
//XElement xeleClass = xeleRoot.Elements("class").Where(x => x.Attribute("number").Value == "0302").Single(); //擷取班級号為0302的直接子節點
//XElement xeleStudent = xeleClass.Elements("student").Where(x => x.Attribute("id").Value == "001").Single(); //擷取學号為001的直接子節點的下一級節點
//xeleStudent.Remove();
Console.WriteLine("删除節點成功!");
例5:修改資料
private static void Update()
XElement xeleClass = xeleRoot.Elements("class").Where(x => x.Attribute("number").Value == "0302").Single(); //擷取班級号為0302的直接子節點
XElement xeleStudent = xeleClass.Elements("student").Where(x => x.Attribute("id").Value == "001").Single(); //擷取學号為001的直接子節點的下一級節點
xeleStudent.SetAttributeValue("id", "008");
xeleStudent.SetElementValue("name", "邦德");
xeleStudent.SetElementValue("gender", "爺們");
xeleStudent.SetElementValue("age", "39");
Console.WriteLine("修改成功!");
查找指定元素
Xml的内容:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<People>
<Person IDCard="22030219901012***">
<Name>張三</Name>
<Sex>男</Sex>
<Age>20</Age>
</Person>
<Person IDCard="22030219921111***">
<Name>李四</Name>
<Sex>女</Sex>
<Age>18</Age>
</People>
代碼:
private void LoadData(string idcard)
string xmlFilePath = "Employee.xml";//xml檔案存放的路徑
XElement xes = XElement.Load(xmlFilePath);//加載xml檔案
if (idcard == "")
//查詢所有的元素
var elements = from ee in xes.Elements("Person")
select new
{
姓名 = ee.Element("Name").Value,
性别 = ee.Element("Sex").Value,
年齡 = ee.Element("Age").Value,
身份證号 = ee.Attribute("IDCard").Value
};
dataGridView1.DataSource = elements.ToList();
else
//查詢指定名稱的元素
where ee.Attribute("IDCard").Value == idcard
private void button1_Click(object sender, EventArgs e)
LoadData(comboBox1.Text);
周遊指定節點的所有對象
private void Form1_Load(object sender, EventArgs e)
XDocument doc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), new XElement("People",
new XElement("Person",
new XAttribute("IDCard", "22030219771012"),
new XComment("身份證号是唯一的"),
new XElement("Name", "張三"),
new XElement("Sex", "男"),
new XElement("Old", 20),
new XText("這是對象文本"))));
IEnumerable<XNode> nods = doc.Element("People").Elements("Person").Nodes();
foreach (XNode nod in nods)
string s = nod.ToString();
label1.Text += s + "\n";
傳回指定節點下的注釋
private void Form1_Load(object sender, EventArgs e)
IEnumerable<XNode> nods = doc.Element("People").Elements("Person").Nodes().OfType<XComment>();
使用Descendants方法通路指定元的父節點
XDocument類的Descendants方法: 該方法用來按文檔順序傳回此文檔或元素的經過篩選的子代元素的集合,集合中隻包括具有比對XName的元素。
文法:public IEnumerable<XElement> Descendants(XName name)
private void Frm_Main_Load(object sender, EventArgs e)
//使用LINQ建立xml檔案的内容
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("People",
new XElement("Person",
new XAttribute("IDCard", "22030219771012***"),
new XElement("Name", "張三"),
new XElement("Sex", "男"),
new XElement("Age", 34)
),
new XAttribute("IDCard", "22030219901111***"),
new XElement("Name", "李四"),
new XElement("Sex", "女"),
new XElement("Age", 20)
)
)
);
XElement eleName = doc.Descendants("Name").Where(itm => itm.Value == "張三").First();//查找值等于"張三"的<Name>元素
XElement xe = eleName.Parent;//擷取父節點
label1.Text=xe.ToString();//将父節點的内容輸出
傳回節點集合中每個節點的所有上級節點
本例隻要用到Extensions類的Ancestors擴充方法和XElement類的Name屬性。
Extensions類的Ancestors擴充方法用來傳回元素集合,其中包含源結合中每個節點的上級。文法格式:public static IEnumerable<XElement> Ancestors<T>(this IEnumerable<T> source) where T:XNode
代碼如下:
private void Frm_Main_Load(object sender, EventArgs e)
//使用LINQ建立XML
IEnumerable<XElement> elements = doc.Element("People").Descendants("Name"); //取所有的Name元素
label1.Text="顯示源元素\n";
foreach (XElement element in elements)//周遊輸出Name元素
label1.Text += "元素名稱:" + element.Name + " 元素值:" + element.Value + "\n";
label1.Text += "顯示每個源元素的祖先元素\n";
foreach (XElement element in elements.Ancestors())//周遊輸出每個Name元素的所有上級節點

傳回節點集合中每個節點的所有下級節點
private void Frm_Main_Load(object sender, EventArgs e)
IEnumerable<XElement> elements = doc.Element("People").Elements("Person");//查詢Person元素
label1.Text += "顯示源元素\n";
foreach (XElement element in elements)//周遊并輸出Person元素
label1.Text += "顯示每個源元素的子孫節點\n";
foreach (XNode nod in elements.DescendantNodes())//周遊并輸出所有的下級節點
label1.Text += "子孫節點:" + nod.ToString() + "\n";
傳回原宿集合中每個元素的所有屬性
private void Frm_Main_Load(object sender, EventArgs e)
new XAttribute("Name", "張三"),
new XAttribute("Sex", "男"),
new XAttribute("Age", 34),
new XElement("IDCard", "22030219771012***")
new XAttribute("Name", "李四"),
new XAttribute("Sex", "女"),
new XAttribute("Age", 20),
new XElement("IDCard", "22030219901111***")
foreach (XElement element in elements)//周遊輸出Person元素
label1.Text += "顯示每個源元素的屬性\n";
foreach (XAttribute attr in elements.Attributes())//周遊每個源元素的屬性
label1.Text += "屬性名稱:" + attr.Name + " 屬性值:" + attr.Value + "\n";
替換指定節點下的所有元素
string path = "new.xml";//取XML檔案的全路徑
XElement xe = XElement.Load(path);//加載XML檔案
//用LINQ查找要修改的元素
IEnumerable<XElement> element = from ee in xe.Elements("Person")
where ee.Attribute("IDCard").Value == "22030219901111***"
&& ee.Element("Name").Value == "李四"
select ee;
if (element.Count() > 0)//存在要修改的元素
XElement first = element.First();//取第一個元素
//全部替換成新的節點
first.ReplaceAll(
new XAttribute("IDCard", "22030219891111XXX"),
new XElement("Name", "李麗"),
new XElement("Sex", "女"),
new XElement("Age", 21)
);
xe.Save(path);//儲存檔案
webBrowser1.Url = new Uri(Application.StartupPath + "\\" + path);//在窗體中顯示XML檔案内容
将XML檔案中的屬性轉換為元素
string xmlFilePath = Application.StartupPath+"\\new.xml";//取XML檔案的全路徑
XElement xe = XElement.Load(xmlFilePath);//加載XML檔案
//用LINQ查找要操作的元素
if (element.Count() > 0) //存在要操作的元素
XElement first = element.First();
XAttribute attribute = first.Attribute("IDCard");//取身份證号屬性
//添加一個名稱和值都與屬性一樣的子元素
first.AddFirst(
new XElement(attribute.Name, attribute.Value)
first.RemoveAttributes();//删除身份證号屬性
xe.Save(xmlFilePath);//儲存XML檔案
webBrowser1.Url = new Uri(xmlFilePath);//在窗體中顯示XML内容