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>
</student>
</class>
</school>
例2:读取XML文件
static string path = "1.xml";
static void Main(string[] args)
{
// 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);
}
}
Console.ReadKey();
}
例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成功");
Console.ReadKey();
}
运行结果:
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成功");
Console.ReadKey();
}
例4:删除数据
private static void DeleteData()
{
XDocument xdoc = XDocument.Load("1.xml");
XElement xeleRoot = xdoc.Root;
//删除根节点的直接子节点
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();
xdoc.Save("1.xml");
Console.WriteLine("删除节点成功!");
Console.ReadKey();
}
例5:修改数据
private static void Update()
{
XDocument xdoc = XDocument.Load("1.xml");
XElement xeleRoot = xdoc.Root;
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");
xdoc.Save("1.xml");
Console.WriteLine("修改成功!");
Console.ReadKey();
}
查找指定元素
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>
</Person>
</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
{
//查询指定名称的元素
var elements = from ee in xes.Elements("Person")
where ee.Attribute("IDCard").Value == idcard
select new
{
姓名 = ee.Element("Name").Value,
性别 = ee.Element("Sex").Value,
年龄 = ee.Element("Age").Value,
身份证号 = ee.Attribute("IDCard").Value
};
dataGridView1.DataSource = elements.ToList();
}
}
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)
{
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().OfType<XComment>();
foreach (XNode nod in nods)
{
string s = nod.ToString();
label1.Text += s + "\n";
}
}
使用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 XElement("Person",
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
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 XElement("Person",
new XAttribute("IDCard", "22030219901111***"),
new XElement("Name", "李四"),
new XElement("Sex", "女"),
new XElement("Age", 20)
)
)
);
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元素的所有上级节点
{
label1.Text += "元素名称:" + element.Name + " 元素值:" + element.Value + "\n";
}
}
返回节点集合中每个节点的所有下级节点
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 XElement("Person",
new XAttribute("IDCard", "22030219901111***"),
new XElement("Name", "李四"),
new XElement("Sex", "女"),
new XElement("Age", 20)
)
)
);
IEnumerable<XElement> elements = doc.Element("People").Elements("Person");//查询Person元素
label1.Text += "显示源元素\n";
foreach (XElement element in elements)//遍历并输出Person元素
{
label1.Text += "元素名称:" + element.Name + " 元素值:" + element.Value + "\n";
}
label1.Text += "显示每个源元素的子孙节点\n";
foreach (XNode nod in elements.DescendantNodes())//遍历并输出所有的下级节点
{
label1.Text += "子孙节点:" + nod.ToString() + "\n";
}
}
返回原宿集合中每个元素的所有属性
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("Name", "张三"),
new XAttribute("Sex", "男"),
new XAttribute("Age", 34),
new XElement("IDCard", "22030219771012***")
),
new XElement("Person",
new XAttribute("Name", "李四"),
new XAttribute("Sex", "女"),
new XAttribute("Age", 20),
new XElement("IDCard", "22030219901111***")
)
)
);
IEnumerable<XElement> elements = doc.Element("People").Elements("Person");//查询Person元素
label1.Text="显示源元素\n";
foreach (XElement element in elements)//遍历输出Person元素
{
label1.Text += "元素名称:" + element.Name + " 元素值:" + element.Value + "\n";
}
label1.Text += "显示每个源元素的属性\n";
foreach (XAttribute attr in elements.Attributes())//遍历每个源元素的属性
{
label1.Text += "属性名称:" + attr.Name + " 属性值:" + attr.Value + "\n";
}
}
替换指定节点下的所有元素
private void Frm_Main_Load(object sender, EventArgs e)
{
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文件中的属性转换为元素
private void Frm_Main_Load(object sender, EventArgs e)
{
string xmlFilePath = Application.StartupPath+"\\new.xml";//取XML文件的全路径
XElement xe = XElement.Load(xmlFilePath);//加载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();
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内容
}