文章部分代码引用参考文章, 文末参考文章已标注 ,本篇文章建立在两篇参考文章基础上,可以先阅读参考文章
XML 相关类
- XDocument
- XmlDocument
- XmlReader XmlWriter
- XNamespace
- XPath
XDocument 和 XmlDocument 这两个类都可以代表 XML 操作对象,可以对XML 内的节点进行操作进行.既然两个都是操作对象,有什么区别呢?
在.NET version 3.0 或是更低 你不得不使用XmlDocument , 而 XDocument 可以结合 LINK TO XML 使用 ,并且在创建XML 时, XD显得更加便捷,看起来更加明朗.见下文创建XML
1 // 创建一个xml文档 XDocument所属命名空间:using System.Xml.Linq; 2 XDocument xDoc = new XDocument(); 3 // 添加根节点 4 XElement xRoot = new XElement("Root"); 5 // 添加节点使用Add 6 xDoc.Add(xRoot); 7 8 // 创建一个学生加到root中 9 // 1、创建学生节点 10 XElement xStudent = new XElement("Student"); 11 12 // 2、创建学生姓名、年龄、性别 13 XElement xName = new XElement("Name"); 14 XElement xAge = new XElement("Age"); 15 XElement xGender = new XElement("Gender"); 16 17 //给每个元素赋值 18 xName.Value = "张三"; 19 xAge.Value = "19"; 20 xGender.Value = "男"; 21 22 // 3、添加节点(没有顺序之分) 23 xStudent.Add(xName, xAge, xGender); //把学生姓名,年龄,性别元素添加到学生节点下 24 xRoot.Add(xStudent); //把学生节点添加到根节点下 25 26 // 为Student添加属性 27 XAttribute xId = new XAttribute("id", ".Net01"); 28 xStudent.Add(xId); 29 30 // 保存该文档 31 xDoc.Save("myxml.xml");
生成的XML
1 <?xml version="1.0" encoding="utf-8"?> 2 <Root> 3 <Student id=".Net01"> 4 <Name>张三</Name> 5 <Age>19</Age> 6 <Gender>男</Gender> 7 </Student> 8 </Root>
而看一下XDocument 的情况
1 static void saveXml2() 2 { 3 //如果你喜欢这样写的话,那就一级一级阶梯状排列好。很有层次感,看起来特明了 4 XDocument xDoc = new XDocument( 5 new XElement("Root", 6 new XElement("FlyInfo", 7 new XElement("Sum", 8 new XElement("AirLine", "航空"), 9 new XElement("Seat", "经济舱"), 10 new XElement("Rating", "A"), 11 new XElement("Gai", "可以改"), 12 new XElement("Tui", "可以退"), 13 new XElement("Qian", "可以签"), 14 new XElement("com", 15 new XElement("comm", "暂无") 16 ) 17 ) 18 ), 19 20 new XElement("FlyInfo", 21 new XElement("Sum", 22 new XElement("AirLine", "航空"), 23 new XElement("Seat", "头等舱"), 24 new XElement("Rating", "R"), 25 new XElement("Gai", "不可以改"), 26 new XElement("Tui", "不可以退"), 27 new XElement("Qian", "不可以签") 28 ) 29 ) 30 ) 31 ); 32 33 xDoc.Save("Test.xml"); 34 }
生成的XML
增加节点
1 //XDocument提供了Load()静态方法 2 XDocument xDoc = XDocument.Load("tableDemo.xml"); //加载xml文档。这里是相对路径 3 //当你生了个儿子。想上户口簿时,就给其父亲加个儿子节点 4 XElement xfa = xDoc.Root.Element("FlyInfo"); //找到父亲(FlyInfo是父节点,所属他下面的都是子节点) 5 XNode xson = xfa.LastNode; //找到最后一个儿子节点 6 7 //这里给父亲添加个儿子(在末尾添加的) 8 xson.AddAfterSelf( 9 new XElement("son","还没生子") //这里son没有儿子。也就是son节点没有子节点 10 ); 11 xDoc.Save("tableDemo.xml"); //保存数据 其实总的来说是把全部数据读到内存中然后在内存中追加数据后再全部保存tableDemo.xml
看结果
1 <?xml version="1.0" encoding="utf-8" standalone="yes"?> 2 <Root> 3 <FlyInfo> 4 <AirLine>航空</AirLine> 5 <Seat>经济舱</Seat> 6 <Rating>A</Rating> 7 <Gai>可以改</Gai> 8 <Tui>可以退</Tui> 9 <Qian>可以签</Qian> 10 <son>还没生子</son> 11 </FlyInfo> 12 </Root>
关于XDocument 对 XML 格式的数据进行操作具体可以点开参考文章进行学习(第一篇文章讲的很详细),下面纪录我在使用XML中遇到的问题。
几种使用场景
-
Xml 格式数据转化为byte
当Xml需要在网络中传输的时候就需要转化为byte
1 public static byte[] XMLtoBytes(string cmd,string ver,string id,string ret) 2 { 3 XDocument xDoc = new XDocument( 4 new XElement("msg", 5 new XElement("header", 6 new XElement("ack", cmd), 7 new XElement("ver", ver), 8 new XElement("id", id)), 9 new XElement("data", 10 new XElement("ret", ret), 11 new XElement("error","must use english")) 12 ) 13 14 ); 15 byte[] byteArray = System.Text.Encoding.Default.GetBytes(xDoc.ToString()); 16 return byteArray; 17 }
可以看到只需要调用 XDocument.ToString( ) 就可以转化为string 再转化为 byte[ ] ,当时坑死我了~~~, 当我需要转化回XML数据的时候,只需要
1 //创建一个内存缓冲区 其大小为1024*1024字节 即1M 2 byte[] arrServerRecMsg = new byte[1024 * 1024]; 3 //将接收到的信息存入到内存缓冲区,并返回其字节数组的长度 4 int length = SocketCmd.Receive(arrServerRecMsg); 5 //将机器接受到的字节数组转换为人可以读懂的字符串 6 string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length); 7 //将发送的字符串信息附加到文本框txtMsg上 8 Msgtextbox.AppendText("接受到的信息为 :" + "\r\n" + strSRecMsg + "\r\n"); 9 10 //现在把它解释成xml 11 XDocument xDocument = XDocument.Parse(strSRecMsg);
这里我是使用Socket接收数据,arrServerRecMsg 即为 xml数据的byte[ ] 数据。当然 XDocument 转为为 string 的方式还有很多种,详见:
-
Xml 带有XmlDeclaration
例如我需要的数据如下:开头需要
<?xml version="1.0"?>
1 <?xml version="1.0"?> 2 <msg> 3 <header> 4 <cmd>CON</cmd> 5 <ver>1.1</ver> 6 <id>4417</id> 7 </header> 8 <data /> 9 </msg>
使用XmlDeclaration
1 private static XDocument BuildmdXMLTemp(string cmd, string ver, string id) 2 { 3 4 XDocument xDoc = new XDocument(new XDeclaration("1.0", null, null), 5 new XElement("msg", 6 new XElement("header", 7 new XElement("cmd", cmd), 8 new XElement("ver", ver), 9 new XElement("id", id)), 10 new XElement("data", 11 null) 12 ) 13 14 ); 15 return xDoc; 16 }
但是这里有个坑,当我传递XML数据转化为byte[ ]进行传递的时候接收的数据我的XmlDeclaration不见了, 查了“爆栈”(stackoverflow)才知道直接时候XmlDocument.Tostring( )方法是不行的,可以有两种方案:
- XmlDeclaration大坑解决方法
- 使用XmlDocument.Save ( ) ,得到 TextWriter,再将数据转为byte[ ] ,需要注意的是这个方法当我的 XmlDeclaration 中包含 utf-8 有可能会变成 utf-16
<?xml version="1.0" encoding="UTF-8"?>
解决方法:
1 using (var mem = new MemoryStream()) 2 using (var writer = new XmlTextWriter(mem, System.Text.Encoding.UTF8)) 3 { 4 writer.Formatting = Formatting.Indented; 5 doc.WriteTo(writer); 6 writer.Flush(); 7 mem.Flush(); 8 mem.Seek(0, SeekOrigin.Begin); 9 using (var reader = new StreamReader(mem)) 10 { 11 var xml = reader.ReadToEnd(); 12 Console.WriteLine(xml); 13 } 14 }
- 另外一种就是
1 string strXML = string.Concat(xDoc.Declaration.ToString(), "\r\n", 2 xDoc.ToString()); 3 byte[] bytes = Encoding.Default.GetBytes(strXML); 4 return bytes;
-
查找Xml数据中是否有某一节点
假如我不知道msg/header 和 msg/data 根节点中是否有 error 和 errorNum 节点,(如果你有更好的方法可以评论一下,互相学习一下)
1 IEnumerable<XElement> xmlElements = xDocument.XPathSelectElements("msg/header/error"); 2 IEnumerable<XElement> xmlElementss = xDocument.XPathSelectElements("msg/data/errorNum"); 3 clientTextBox.AppendText(xmlElements.Count().ToString()); 4 if (xmlElements.Any()) 5 { 6 7 foreach (XElement element in xmlElements) 8 { 9 if (element.Name.ToString().Equals("error")) 10 { 11 clientTextBox.AppendText("请求: " + ack + " " + "出现错误: " + element.Value + "\r\n"); 12 } 13 clientTextBox.AppendText(element.Value.ToString() + "\r\n"); 14 } 15 }
开始的时候,写成这样会报错,得不到引用
1 string ret = xDocument.XPathSelectElement("msg/data/errorNum").Value.ToString()
-
序列化
序列化可看第二篇参考文章,需要指出的是,第二篇文章,XML 使用的使用将XML 数据序列化成对象,这种方法需要一个前提的条件就是当我的数据结构是不变的情况下,例如本文中上一个使用场景,我不知道某个根节点中是否存在某一个节点,那么就无法构建对象了,因为我不知传过来的数据是否会有这个节点,有可能有,也有可能没有,要是这种情况的话,先把Xml数据序列化转为 byte[ ] ,利用XDocument.parse( string data ) 方法,然后再进行判断是否有这个节点.
参考文章 :