知识点:理解 XML 语言 、掌握 XML 文件的解析、掌握 XML节点的添加和删除操作
XML(可扩展标记语言,eXtensible Markup Language)可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。它非常适合万维网传输,提供统一的方法来描述和交换 独立于应用程序或供应商的结构化数据。是 Internet 环境中跨平台的、依赖于内容的技术,也是当今处理分布式结构信息的有效工具。早在 1998 年,W3C 就发布了 XML1.0 规范,使用它来简化 Internet 的文档信息传输。
使用 XML 标记语言可以做到数据或数据结构在任何编程语言环境下的共享。例如我们在某个计算机平台上用某种编程语言编写了一些数据或数据结构,然后用 XML 标记语言进行处理,那样的话,其他人就可以在其他的计算机平台上来访问这些数据或数据结构,甚至可以用其他的编程语言来操作这些数据或数据结构了。这就是 XML 标记语言作为一种数据交换语言存在的价值。
XML 可以理解为一辆没有发动机的车。 XML 把所有部件按照一定规则集合在一起,就等编译器这个发动机去启动这个车。现在用的比较多的是配置和数据结构定义。.NET 平台中的 Web 服务(WebService)和前台应用程序的数据交互,以及网站、应用程序的配置信息都大量使用了 XML。例如WinForm里面的app.config以及Web程序中的web.config文件,还有许多重要的场所都有它的身影。
张三
20
男
李四
22
男
王迪
18
女
是一个XML处理指令。
XML 文档内容由多个节点组成,
通过前面 XML 的示例,大家会发现 XML 和 HTML 的结构类似,都有大量的标记构成,但 HTML 主要用于定义网页,而 XML 则主要用于描述数据以实现系统间的数据传输。 XML 的特点:
Everyday Italian
Giada De Laurentiis
2005
30.00
Harry Potter
J K. Rowling
2005
29.99
Learning XML
Erik T. Ray
2003
39.95
我们看到这个 XML 文件XML 文件比 示例1的persons.xml 稍复杂些,主要是根节点下的
XML文档树:
使用任何文本编辑器都可以创建 XML 文件,在一些专业的开发工具(如 Visio Studio)中创建 XML 文件会有更多方便的功能,如:自动补全结束标记和格式检查等。 在 Visio Studio 项目中创建 XML 文件:
1)在【解决方案资源管理器】中,右键点击项目名称,依次点击【添加】→【新建项】
2)在弹出的窗口中,点击【数据】→【XML 文件】,根据需要修改名称,最后点击【添加】即可。
既然 XML 是在 Internet 中进行数据传输的主要格式之一,那么应用程序接收到 XML 数据后,将其解析成系统能够接受的格式,就是一项非常重要的操作了。
在程序中访问进而操作XML文件一般有两种模型,分别是使用DOM(文档对象模型)和流模型,使用DOM的好处在于它允许编辑和更新XML文档,可以随机访问文档中的数据,可以使用XPath查询,但是,DOM的缺点在于它需要一次性的加载整个文档到内存中,对于大型的文档,这会造成资源问题。流模型很好的解决了这个问题,因为它对XML文件的访问采用的是流的概念,也就是说,任何时候在内存中只有当前节点,但它也有它的不足,它是只读的,仅向前的,不能在文档中执行向后导航操作。
使用XmlDocument是一种基于文档结构模型的方式来读取XML文件。在XML文件中,我们可以把XML看作是由文档声明(Declare),元素(Element),属性(Attribute),文本(Text)等构成的一个树。最开始的一个结点叫作根结点,每个结点都可以有自己的子结点。得到一个结点后,可以通过一系列属性或方法得到这个结点的值或其它的一些属性。例如:
1: xn 代表一个结点
2: xn.Name;//这个结点的名称
3: xn.Value;//这个结点的值
4: xn.ChildNodes;//这个结点的所有子结点
5: xn.ParentNode;//这个结点的父结点
C# 中对 XML 进行操作的类保存在 System.Xml 命名空间下。
类
|
属性和方法
|
说明 |
XmlDocument
|
DocumentElement
属性
|
文档根节点
|
ChildNodes
属性
|
所有子节点集合
|
|
Load
方法
|
加载文档
|
|
XmlNode
|
InnerText
属性
|
节点内容
|
Name
属性
|
节点名字
|
|
ChildNodes
属性
|
当前节点的子节点集合
|
XmlDocument 类代表整个文档,用 Load 方法加载 XML 文件,使用 DocumentElement 属性获得根节点,XmlNode 类代表 Xml 节点,例如:
1)创建 XmlDocument 对象
2)调用 Load 方法加载文档
3)使用 DocumentElement 属性获得根节点
4)遍历根节点下的子节点集合
5)读取子节点的 Name 和 InnerText 属性
要求:解析示例 1 中的 persons.xml 文件,将人的信息输出在控制台中。
第一步,新建项目:①在VS中新建控制台应用(.NET Framework),这里默认命名为【ConsoleApp7】,单击【确定】按钮,自动完成创建,并打开项目。
第二步,新建XML文件:右键单击【解决方案资源管理器】中项目名称【ConsoleApp7】,依次单击【添加】→【新建项】,在弹出的窗口中点击【XML】文件,并将文件命名为persons.xml ,然后单击【添加】,自动完成创建,并打开persons.xml 文件。(此步骤可以参照示例2)
第三步,编写XML文件:在当前打开的persons.xml 文件中,编写内容。(具体代码,参照示例1)
第四步,移动XML文件的位置:为了便于读取 XML 文件,我们将 persons.xml 文件添加到项目的/bin/debug 目录下。点击解决方案资源管理器上的【显示所有文件】按钮,找到/bin/Debug 目录,将文件拖进去。
单击【确定】按钮
拖拽完成后
第五步,在主程序中写代码:在Program.cs文件中的Main方法里,编写代码,进行 XML 文件的解析
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument(); //new一个对象,注意引用命名空间
doc.Load("persons.xml"); //使用Load()方法,加载文档
XmlNode root = doc.DocumentElement;//获取根节点,并存在root里
//遍历输出子节点
foreach(XmlNode node in root.ChildNodes)//获取根节点下的,子节点结合
{
switch (node.Name)//获取子节点名称,作为表达式
{
case "name":
Console.WriteLine("姓名:"+node.InnerText);//读取子节点的InnerText属性
break;
case "age":
Console.WriteLine("年龄:" + node.InnerText);
break;
case "gender":
Console.WriteLine("性别:" + node.InnerText);
break;
}
}
Console.ReadLine();
}
预览效果:
我们在程序中除了可以解析 XML 数据外,还可以添加、更新和删除 XML 节点。
要求:在示例3的基础上,在 persons.xml 文件中,添加节点
实现步骤:在示例3第五步的基础上,增加“添加节点”的关键代码。4个步骤实现:创建节点→设置节点内容→将节点添加到根节点里→保存xml文件的修改。
代码分析:这部分代码关键的是:先调用 XmlDocument 对象的 CreateElement 方法创建一个 XmlElement 对象, XmlElement 是 XmlNode 的父类,这里简单起见我们也把它看作是一个节点。后面通过 InnerText 设置节点的内容,然后通过 XmlNode 节点的 AppendChild 方法在根节点 root 中添加了新建的子节点,最后操作 完毕后调用 XmlDocument 的 Save 方法保存文件。
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument(); //new一个对象,注意引用命名空间
doc.Load("persons.xml"); //使用Load()方法,加载文档
XmlNode root = doc.DocumentElement;//获取根节点,并存在root里
//①创建节点
XmlElement eName = doc.CreateElement("name");
//②设置节点内容
eName.InnerText = "jack";
//③将节点eName添加到根节点中
root.AppendChild(eName);
//④保存文件的修改
doc.Save("persons.xml");
//遍历输出子节点
foreach(XmlNode node in root.ChildNodes)
{
switch (node.Name)
{
case "name":
Console.WriteLine("姓名:"+node.InnerText);
break;
case "age":
Console.WriteLine("年龄:" + node.InnerText);
break;
case "gender":
Console.WriteLine("性别:" + node.InnerText);
break;
}
}
Console.ReadLine();
}
运行预览:
案例思考:
①给jack添加上对应的年龄、性别。(继续增加节点)
②如何给节点新增加属性?(语法:节点名称.SetAttribute("属性名称","属性值");)
在 XML 中删除节点的思路是:找到要删除的子节点,调用父节点的 RemoveChild 方法将其删除,然后调用 XmlDocument 的 Save 方法。
要求:在示例4的基础上,在 persons.xml 文件中,删除节点
实现步骤:在示例3第五步的基础上,增加“删除节点”的关键代码。
//①找到要删除的节点
XmlNode xmlNode = root["name"];
//②使用RemoveChild()方法,删除子节点
root.RemoveChild(xmlNode);
//③保存文件的修改
doc.Save("persons.xml");
预览结果:只删除了第一个子节点
案例思考:如何实现以下需求?
1、一次性删除案例中所有的name节点
2、删除案例中指定的name节点
在 XML 中删除节点的思路是:找到要删除的子节点,调用父节点的 RemoveChild 方法将其删除,然后调用 XmlDocument 的 Save 方法。
要求:解析给定的 bookstore.xml 文件,并修改节点和节点属性
1)给定的 bookstore.xml 文件
Oberon's Legacy
delia
5.95
CS从入门到精通
delia
58.3
2)修改节点属性值,例如将genre属性是“王迪”的值,修改为update王迪。
static void Main(string[] args)
{
XmlDocument xmlDoc = new XmlDocument();//①创建文档对象
xmlDoc.Load("bookstore.xml");//②加载xml文档
XmlNodeList nodeList = xmlDoc.SelectSingleNode("bookstore").ChildNodes;//③获取bookstore节点的所有子节点,存放在nodeList里
foreach (XmlNode xn in nodeList)//④遍历所有子节点
{
XmlElement xe = (XmlElement)xn;//⑤将子节点类型转换为XmlElement类型
if (xe.GetAttribute("genre") == "王迪")//⑥判断,如果genre属性值为“王迪”
{
xe.SetAttribute("genre", "update王迪");//则修改该属性为“update王迪”
}
}
xmlDoc.Save("bookstore.xml");//保存。
Console.ReadLine();
}
3)修改节点内容,例如,将author节点的内容,修改为delia11
static void Main(string[] args)
{
XmlDocument xmlDoc = new XmlDocument();//①创建文档对象
xmlDoc.Load("bookstore.xml");//②加载xml文档
XmlNodeList nodeList = xmlDoc.SelectSingleNode("bookstore").ChildNodes;//③获取bookstore节点的所有子节点,存放在nodeList里
foreach (XmlNode xn in nodeList)//④遍历bookstorde的所有子节点
{
XmlElement xe = (XmlElement)xn;//⑤将子节点类型转换为XmlElement类型
XmlNodeList nls = xe.ChildNodes;//继续获取xe子节点的所有子节点
foreach (XmlNode xn1 in nls)//遍历xe子节点的所有子节点
{
XmlElement xe2 = (XmlElement)xn1;//转换类型
if (xe2.Name == "author")//如果找到
{
xe2.InnerText = "delia11";//则修改
}
}
}
xmlDoc.Save("bookstore.xml");//保存
Console.ReadLine();
}
要求:解析给定的 cars.xml 文件
第一步,新建项目:在VS中新建控制台应用(.NET Framework),这里默认命名为【ConsoleApp7.1】,单击【确定】按钮,自动完成创建,并打开项目。
第二步,添加汽车类Car:在右侧【解决方案资源管理器中】,右键单击项目名称【ConsoleApp7.1】,依次点击【添加】→【类】,在弹出的【添加新项】窗口中,给类起一个名字Car.cs,然后点击【添加】,添加成功后会默认打开Car.cs文件,在里面编写对应的内容(本案例是为了练习解析xml文件,因此可以直接复制代码)
//变速箱类型枚举
public enum GearShift
{
手动档, 自动档
}
//汽车类
public class Car
{
//使用构造方法
public Car(string lisenceNo, GearShift gearShift, string type, double emission, double oilUsage)
{
this.LisenceNo = lisenceNo;
this.GearShift = gearShift;
this.Type = type;
this.Emission = emission;
this.OilUsage = oilUsage;
}
public Car() { }
public string LisenceNo { get; set; }
public GearShift GearShift { get; set; }
public string Type { get; set; }
public double Emission { get; set; }
public double OilUsage { get; set; }
public string Introduce()
{
return string.Format("这辆车的牌照是{0},{1},车型是{2},排量为{3}升,油耗为{4}升/100km",
LisenceNo, GearShift, Type, Emission, OilUsage);
}
public virtual string Run()
{
return string.Format("{0}牌照的汽车正在路上行驶", LisenceNo);
}
}
第三步,添加子类公共汽车Bus:在当前项目中添加一个公共汽车类Bus,在系统会默认打开的Bus.cs文件中,编写公共汽车类相关信息
///
/// 公共汽车
///
class Bus :Car
{
public Bus(string lisenceNo, GearShift gearShift, string type,
double emission, double oilUsage,int maxNumberOfPassengers,int numberOfPassengers)
:base(lisenceNo,gearShift,type,emission,oilUsage)
{
this.MaxNumberOfPassengers = maxNumberOfPassengers;
this.NumberOfPassengers = numberOfPassengers;
}
public Bus() { }
public int MaxNumberOfPassengers { get; set; }
public int NumberOfPassengers { get; set; }
public string GetOnPassengers(int number)
{
if (this.NumberOfPassengers + number > this.MaxNumberOfPassengers)
{
return "乘客超载,不能上车";
}
else
{
this.NumberOfPassengers += number;
return string.Format("到站上车乘客{0}人,共有{1}人",number,NumberOfPassengers);
}
}
public string GetOffPassengers(int number)
{
if (this.NumberOfPassengers - number < 0)
{
return "乘客人数不足";
}
else
{
this.NumberOfPassengers -= number;
return string.Format("{0}公交车,到站上车乘客{1}人,共有{2}人", LisenceNo, number, NumberOfPassengers);
}
}
public override string Run()
{
return string.Format("{0}牌照的公交车正在路上行驶", LisenceNo);
}
}
第四步,添加子类吊车Crane:在当前项目中添加一个吊车类Crane,在系统会默认打开的Crane.cs文件中,编写吊车类相关信息
///
/// 吊车类
///
class Crane : Car
{
public Crane(string lisenceNo, GearShift gearShift, string type,
double emission, double oilUsage, int maxWeightOfGoods)
: base(lisenceNo, gearShift, type, emission, oilUsage)
{
this.MaxWeightOfGoods = maxWeightOfGoods;
}
public Crane() { }
public int MaxWeightOfGoods { get; set; }
public string HoistGoods(int weight)
{
if (weight > this.MaxWeightOfGoods)
{
return string.Format("货物超重,{0}起吊失败",LisenceNo);
}
else
{
return string.Format("{0}吊车,吊起货物{1}吨", LisenceNo, weight);
}
}
public override string Run()
{
return string.Format("{0}牌照的吊车正在路上行驶", LisenceNo);
}
}
第五步,新建XML文件:右键单击【解决方案资源管理器】中项目名称【ConsoleApp7.1】,依次单击【添加】→【新建项】,在弹出的窗口中点击【XML】文件,并将文件命名为cars.xml ,然后单击【添加】,自动完成创建,在打开的cars.xml 文件中编写代码。完成以后,将cars.xml文件拖拽到当前项目的/bin/Debug 目录里。(此步骤,参照示例3)
鄂A554335
手动档
大众高尔夫
1.5
6
鄂A676767
自动档
奥迪Q7
3.5
12
鄂B757575
手动档
东风小型
5.0
15
20
鄂C123456
手动档
东风中型
5.5
18
25
鄂C876543
手动档
中联C1001
7.0
20
4
鄂C547790
手动档
中联C2002
7.5
20
5
第五步,在主程序中写代码:在Program.cs文件中的Main方法里,编写代码,进行 XML 文件的解析
代码分析:这里使用C#解析 XML 文档的步骤,和示例3 是一样的,只不过由于 XML文档本身较复杂一些,因此再解析的时候,多增加了一些内容。
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();//①创建XmlDocument对象,这里给对象起名doc
doc.Load("cars.xml");//②调用对象(doc)的Load方法,加载指定的xml文档
XmlNode root = doc.DocumentElement;//③使用对象(doc)的DocumentElement属性,获得根节点
foreach (XmlNode node in root.ChildNodes)//④遍历根节点下的,子节点集合root.ChilNodes
{
switch (node.Attributes["class"].Value)//获取节点属性class的值,作为switch选择结构的表达式
{
case "Car": //如果class属性值是“Car”,执行以下语句
Car car = new Car();//创建一个汽车类对象Car
//给对象Car的属性赋值,通过“节点名称["子节点名称"].InnerText”,获得子节点内容,并赋值给Car对象的对应属性
car.LisenceNo = node["lisenceNo"].InnerText;
car.Type = node["type"].InnerText;
car.GearShift = node["gearShift"].InnerText == "手动档" ? GearShift.手动档 : GearShift.自动档;//先使用三元运算符判断结果,然后赋值给属性
car.Emission = double.Parse(node["emission"].InnerText);
car.OilUsage = double.Parse(node["oilUsage"].InnerText);
Console.WriteLine(car.Introduce()); //输出,对象Car的Introduce()方法
break;
case "Bus":
Bus bus = new Bus();//创建一个公交车类对象Bus
bus.LisenceNo = node["lisenceNo"].InnerText;
bus.Type = node["type"].InnerText;
bus.GearShift = node["gearShift"].InnerText == "手动档" ? GearShift.手动档 : GearShift.自动档;
bus.Emission = double.Parse(node["emission"].InnerText);
bus.OilUsage = double.Parse(node["oilUsage"].InnerText);
bus.MaxNumberOfPassengers = int.Parse(node["maxNumberOfPassengers"].InnerText);
Console.WriteLine(bus.GetOnPassengers(10));
break;
case "Crane":
Crane crane = new Crane();
crane.LisenceNo = node["lisenceNo"].InnerText;
crane.Type = node["type"].InnerText;
crane.GearShift = node["gearShift"].InnerText == "手动档" ? GearShift.手动档 : GearShift.自动档;
crane.Emission = double.Parse(node["emission"].InnerText);
crane.OilUsage = double.Parse(node["oilUsage"].InnerText);
crane.MaxWeightOfGoods = int.Parse(node["maxWeightOfGoods"].InnerText);
Console.WriteLine(crane.HoistGoods(5));
break;
}
}
Console.ReadLine();
}
预览效果:
新增内容:
1)获取节点属性的方法:节点名称.Attributes["属性名称"].Value
attributes 属性返回包含被选节点属性的 NamedNodeMap(一个无顺序的节点列表),访问属性有两种方法:[索引]或[属性名],Value 是属性的值。
2)获取子节点内容的方法:节点名称["子节点名称"].InnerText
访问当前节点的子节点方式:节点对象[索引]或[子节点名],子节点同样是 XmlNode 类型,可以通 过 InnerText 获得节点内容。
=============这里是结束分割线================