在實際項目中遇到一些關於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());//指定映射規則 忽視沒有的屬性 });
