xml基本操作
在实际项目中遇到一些关于xml操作的问题,被逼到无路可退的时候终于决定好好研究xml一番。xml是一种可扩展标记语言,可跨平台进行传输,因此xml被广泛的使用在很多地方。
本文由浅入深,首先就xml的基本操作增删改查进行简单介绍,接着对最近公司里面的一个项目中所涉及到xml的一些基本应用加以说明,最后介绍到xml不经常使用的命名空间问题,都是一些关于xml最基本的应用,本文在这里只是记录,以备以后查阅。
xml常用方法:
定义xml文档:XmlDocument xmlDoc = new XmlDocument(); 初始化xml文档:xmlDoc.Load("D:\\book.xml");//找到xml文件 创建根元素:XmlElement xmlElement = xmlDoc.CreateElement("", "Employees", ""); 创建节点:XmlElement xeSub1 = xmlDoc.CreateElement("title"); 查找Employees节点:XmlNode root = xmlDoc.SelectSingleNode("Employees"); 添加节点:xe1.AppendChild(xeSub1); 更改节点的属性:xe.SetAttribute("Name", "李明明"); 移除xe的ID属性:xe.RemoveAttribute("ID"); 删除节点title:xe.RemoveChild(xe2);
1 创建xml文档
因为比较简单,直接写方法及结果。
public void CreateXMLDocument() { XmlDocument xmlDoc = new XmlDocument(); //加入XML的声明段落,<?xml version="1.0" encoding="gb2312"?> XmlDeclaration xmlDeclar; xmlDeclar = xmlDoc.CreateXmlDeclaration("1.0", "gb2312", null); xmlDoc.AppendChild(xmlDeclar); //加入Employees根元素 XmlElement xmlElement = xmlDoc.CreateElement("", "Employees", ""); xmlDoc.AppendChild(xmlElement); //添加节点 XmlNode root = xmlDoc.SelectSingleNode("Employees"); XmlElement xe1 = xmlDoc.CreateElement("Node"); xe1.SetAttribute("Name", "李明"); xe1.SetAttribute("ISB", "2-3631-4"); //添加子节点 XmlElement xeSub1 = xmlDoc.CreateElement("title"); xeSub1.InnerText = "学习VS"; xe1.AppendChild(xeSub1); XmlElement xeSub2 = xmlDoc.CreateElement("price"); xe1.AppendChild(xeSub2); XmlElement xeSub3 = xmlDoc.CreateElement("weight"); xeSub3.InnerText = "20"; xeSub2.AppendChild(xeSub3); root.AppendChild(xe1); xmlDoc.Save("D:\\book.xml");//保存的路径 }
结果:
<?xml version="1.0" encoding="GB2312"?> -<Employees>- <Node ISB="2-3631-4" Name="李明"> <title>学习VS</title>- <price> <weight>20</weight> </price> </Node> </Employees>
2 增加节点
XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load("D:\\book.xml");//找到xml文件 XmlNode root = xmlDoc.SelectSingleNode("Employees");//查找Employees节点 XmlElement xe1 = xmlDoc.CreateElement("Node2");//添加Node2节点 xe1.SetAttribute("Name", "张三"); XmlElement xeSub1 = xmlDoc.CreateElement("title");//定义子节点 xeSub1.InnerText = "心情好"; xe1.AppendChild(xeSub1);//添加节点到Node2 root.AppendChild(xe1);//添加节点到Employees xmlDoc.Save("D:\\book.xml");
结果:
<?xml version="1.0" encoding="GB2312"?> -<Employees> -<Node ISB="2-3631-4" Name="李明"> <title>学习VS</title>- <price> <weight>20</weight> </price> </Node>- <Node2 Name="张三"> <title>心情好</title> </Node2>- <Node2 Name="张三"> <title>心情好</title> </Node2> </Employees>
3 修改节点:
public void ModifyNode() { XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load("D:\\book.xml"); XmlNodeList nodeList = xmlDocument.SelectSingleNode("Employees").ChildNodes;//获取Employees节点的所有子节点 foreach (XmlNode xn in nodeList)//遍历 { XmlElement xe = (XmlElement)xn; if (xe.GetAttribute("Name") == "李明") { xe.SetAttribute("Name", "李明明");//更改节点的属性 XmlNodeList xnl = xe.ChildNodes;//获取xe的所有子节点 foreach (XmlNode xn1 in xnl) { XmlElement xe2 = (XmlElement)xn1;//将节点xn1的属性转换为XmlElement if (xe2.Name == "title")//找到节点名字为title的节点 { xe2.InnerText = "今天天气不好"; } if (xe2.Name == "price") { XmlNodeList xnl2 = xe2.ChildNodes; foreach (XmlNode xn2 in xnl2) { if (xn2.Name == "weight") { xn2.InnerText = "88"; } } } } } } xmlDocument.Save("D:\\book2.xml"); } result: <?xml version="1.0" encoding="GB2312"?> -<Employees> -<Node ISB="2-3631-4" Name="李明明"> <title>今天天气不好</title>-<price> <weight>88</weight> </price> </Node> -<Node2 Name="张三"> <title>心情好</title> </Node2></Employees>
4 删除节点:
public void DeleteNode() { XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load("D:\\book1.xml"); XmlNodeList xnl = xmlDocument.SelectSingleNode("Employees").ChildNodes; foreach (XmlNode xn in xnl) { if (xn.Name == "Node") { XmlElement xe = (XmlElement)xn;//将xn的属性转换为XmlElement xe.RemoveAttribute("ID");//移除xe的ID属性 XmlNodeList xnl2 = xe.ChildNodes; for (int i = 0; i < xnl2.Count; i++) { XmlElement xe2 = (XmlElement)xnl2.Item(i); if (xe2.Name == "title") { xe.RemoveChild(xe2);//删除节点title } } } } xmlDocument.Save("D:\\book3.xml"); } 结果: <?xml version="1.0" encoding="GB2312"?> -<Employees> -<Node ISB="2-3631-4" Name="李明">-<price> <weight>20</weight> </price> </Node>- <Node2 Name="张三"> <title>心情好</title> </Node2>- <Node2 Name="张三"> <title>心情好</title> </Node2> </Employees>
前面介绍了xml的创建、节点的添加、节点的修改和删除,下面以写的一个保存项目配置文件的小例子。
举例说明:
首先在项目文件中创建一个xml文档:
<?xml version="1.0" encoding="utf-8" ?> <configurationN> <ServerAddress>1143</ServerAddress> <ID>192.168</ID> </configurationN>
在保存配置文件时,最主要使用了两个方法:Load和Save。
Load:初始化xml文档,以便项目文件获取具体的xml节点的值。
public void Load(string path) { try { XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(path); XmlNodeList xnl = xmlDocument.SelectSingleNode(managerNode).ChildNodes; foreach (XmlNode xn in xnl) { if (xn.Name == configuration_ServerAddress) { ServerAddress = xn.InnerText; } } } catch(Exception ex) { } }
Save:在项目系统中进行修改配置文件值后,需要对xml进行重新保存
public void Save(string path) { try { XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(path); XmlNodeList xnl = xmlDocument.SelectSingleNode(managerNode).ChildNodes; foreach (XmlNode xn in xnl) { if (xn.Name == configuration_ServerAddress) { xn.InnerText = ServerAddress; } } xmlDocument.Save(path); } catch (Exception ex) { } }
此处将所有代码都贴出来,方便下次实现。因为项目是WPF文件,而且都是简单控件,所以只贴出后台代码。
class ConfigurationManager:INotifyPropertyChanged { public const string managerNode = "configurationN";//根节点 public const string configuration_ServerAddress = "ServerAddress";//子节点 private string _ServerAddress; public string ServerAddress { get { return _ServerAddress; } set { _ServerAddress = value; NotifyPropertyChanged("ServerAddress"); } } public void Load(string path) { try { XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(path); XmlNodeList xnl = xmlDocument.SelectSingleNode(managerNode).ChildNodes; foreach (XmlNode xn in xnl) { if (xn.Name == configuration_ServerAddress) { ServerAddress = xn.InnerText; } } } catch(Exception ex) { } } public void Save(string path) { try { XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(path); XmlNodeList xnl = xmlDocument.SelectSingleNode(managerNode).ChildNodes; foreach (XmlNode xn in xnl) { if (xn.Name == configuration_ServerAddress) { xn.InnerText = ServerAddress; } } xmlDocument.Save(path); } catch (Exception ex) { } } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public static ConfigurationManager Instance = new ConfigurationManager(); } public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Start(); this.tb1.Text = ConfigurationManager.Instance.ServerAddress.ToString(); } private string path = "CONFIG\\System.xml"; private void button1_Click(object sender, RoutedEventArgs e) { ConfigurationManager.Instance.ServerAddress = this.tb1.Text; ConfigurationManager.Instance.Save(path); } private void button2_Click(object sender, RoutedEventArgs e) { Application.Current.Shutdown(); } private void Start() { ConfigurationManager.Instance.Load(path); } }
记录在项目中使用xml的实例:
背景:
公司内部系统和第三方系统做对接,http请求得到一个string格式的xml文档,里面包含了大量的字段数据需要解析,如果遍历xml的节点查找节点值也能做,可要是在代码里面写这么多if条件语句,感觉对不起自己写几年代码了。于是有了以下记录,是实际项目的简化版,只介绍思路。
http请求得到的xml:
string strXml =@"<Body> <Result><Code>0</Code><Msg>OK</Msg></Result> <Test><name>data1</name><age>data2</age><score>data3</score></Test></Body>";
为了解析Test的子节点里面的值,编写对应的类,注意,类名一定要对应。
public class Test { public string name { get; set; } public string age { get; set; } public string score { get; set; } }
解析xml代码如下:
XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml(strXml); string testrXml = xmlDocument.SelectSingleNode("Body").SelectSingleNode("Test").OuterXml; XmlSerializer serializer = new XmlSerializer(typeof(Test)); using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(testrXml))) { Test mm = (Test)serializer.Deserialize(memoryStream); }
补充一点,如果想得到固定格式里面的某个节点的value值,可以使用:
string codeValue = xmlDocument.SelectSingleNode("Body").SelectSingleNode("Result").SelectSingleNode("Code").InnerText;
在前面得到一个Test对象,里面的字段都是需要的值。但是如果需要转换为另外一个系统内已经确定的类,还需要做下面操作:
目标类:
public class DestTest { public string name { get; set; } public string age { get; set; } public string totalScore { get; set; } }
其中totalScore字段不一致。
处理方法:
using AutoMapper; public static DestTest GetDto(Test test) { Mapper.Initialize(m => m.CreateMap<Test, DestTest>().ForMember(dest => dest.totalScore, opt => opt.MapFrom(src => src.score))); return Mapper.Map<Test, DestTest>(test); }
补充:
xml带有命名空间,解析的方式和上文不同,下面记录。
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body> <RunServiceResponse xmlns="http://tempuri.org/"> <RunServiceResult>0</RunServiceResult> <outMsg> <Body> <Result><Code>7</Code><Msg>OK</Msg></Result> </Body> </outMsg> </RunServiceResponse> </s:Body> </s:Envelope>
解析如下:
XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(outMsg2);//outMsg2是xml路径 XmlNamespaceManager xmlnsm = new XmlNamespaceManager(xmlDocument.NameTable); xmlnsm.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/"); xmlnsm.AddNamespace("m", "http://tempuri.org/"); XmlNode node = xmlDocument.SelectSingleNode("/s:Envelope", xmlnsm); XmlNode nodeBody = xmlDocument.SelectSingleNode("/s:Envelope/s:Body", xmlnsm); XmlNode nodeResult = xmlDocument.SelectSingleNode("/s:Envelope/s:Body/m:RunServiceResponse/m:outMsg/m:Body/m:Result", xmlnsm); string codeValue = xmlDocument.SelectSingleNode("/s:Envelope/s:Body/m:RunServiceResponse/m:outMsg/m:Body/m:Result/m:Code",xmlnsm).InnerText;
找到节点,其它的和普通xml文件类似。
补充2:
写个小实例,描述对AutoMapper的基本应用:
两个实体类:Test,TestDto:
public class Test { public int Id { get; set; } public string Name { get; set; } public int Score { get; set; } public int Age { get; set; } } public class TestDto { public int Id { get; set; } public string Name { get; set; } public int Result { get; set; } public int Birth { get; set; } }
初始化实体类:
Test test = new Test{Id = 1,Name = "张三",Score = 99, Age=34};
创建映射:
AutoMapper.Mapper.Initialize(m => { m.CreateMap<Test, TestDto>() //创建映射 .ForMember(dest => dest.Result, opt => opt.MapFrom(src => src.Score)); //指定映射规则 });
调用:
TestDto dto = AutoMapper.Mapper.Map<Test, TestDto>(test);
完毕。
附录:
AutoMapper.Mapper.Initialize(m=> { m.CreateMap<test, testDTO>()//创建映射 .ForMember(dest => dest.ArticleID, opt => opt.MapFrom(src => src.Id))//指定映射规则 .ForMember(dest => dest.Summary, opt => opt.MapFrom(src => src.Content.Substring(0, 10)))//指定映射规则 .ForMember(dest => dest.PostYear, opt => opt.MapFrom(src => src.PostTime.Year))//指定映射规则 .ForMember(dest => dest.Remark, opt => opt.Ignore());//指定映射规则 忽视没有的属性 });