还是由于工作的需要,要进行解析XML配置表,虽然感觉XML很简单,因为之前对XML完全空白,所以只能从头学起,那就只能从google开始,找到一些参考①②③见文末,但是总感觉比较零散、混乱,功能不全,只能是例子不能成为工具,所以一直想找一个基本可以满足所有需求的实现。大概熟悉了XML的结构(还是花了好久,虽然比较简单,但是要很C#api中的Node,Element,Attribute等概念对应分得清要一点时间去消化)和C# XmlDocument的api,感觉通过api去实现一些功能还是比较困难或者比较直观,比如我要查找含有属性“lang”的所有结点,这个大概想了下要得遍历,所以迟迟未动手,知道我找到参考④。看了④的文章,很是惊奇,惊呼——原来还有这个东西(Xpath),顿时觉得希望实现自己想要的功能。然后就去查阅W3C School的Xpath的规范。
有了想法之后,总是忍不住的想动手,刚开始的想法是定义一个StringBuilder xpath变量,然后往后面添加相关操作的Xpath字符串,但是还是感觉情况太多了,函数命名都成问题了(我记得一直命名到AddNode9()),总感觉做的是字符匹配的过程,但是有没有“正则表达式”的智能,然后我有想起一直的困惑——对于情况很多再加上不同情况的组合的问题解决起来很被动,有种被耍的感觉。那只有彻底解决,其实这就是“正则表达式”的原理——有限状态机,好在我之前看过“有限状态机”的理论。
我早上三点起来(哎,一直挺矛盾的),我在CodeProject上找FSM的代码(还真不少),果断下载了几个,对代码仔细研读一番,最后感觉这个问题用FSM实在是大材小用,发现之前感觉的“不智能”都不会了,可以通过约束使用规范避免,所以还是回归到Xpath上,然后就有了下面的代码(测试了几个都没有问题),后面部分(有注释的直接copy③),实在是没有时间(一会还要去上班),然后就是功能还不完善,以后有时间一并补上(如果你有补充希望能够分享下,谢谢)。
下面的代码(假定你具有Xpath的基础)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; /// Code By D.S.Qiu namespace XmlParse { class XmlUtils { public static StringBuilder xpath = new StringBuilder(); public static XmlDocument xmlDoc=new XmlDocument(); public static XmlElement root = null; public static void AddCommint(string commit) { xpath.Append(commit); } public static void AddNode(string name) { xpath.Append("/" + name); } public static void AddNodeRegardlessPosition(string name) { xpath.Append("//" + name); } public static void AddNodeByIndex(string name, string index) { xpath.Append("/" + name + "[" + index + "]"); } public static void AddNodeByIndexRegardlessPosition(string name, string index) { xpath.Append("//" + name + "[" + index + "]"); } public static void AddNodeByValue(string name, string value, string operatorstr = "=") { xpath.Append("[" + name + operatorstr + value + "]"); } public static void AddIndex(string index) { xpath.Append("[" + index + "]"); } public static void AddAttribute(string name) { xpath.Append("[@" + name + "]"); } public static void AddAttributeByValue(string name, string value,string operatorstr="=") { xpath.Append("[@" + name +operatorstr+value+ "]"); } public static void AddAnyNode() { xpath.Append("/*" ); } public static void AddAnyNodeRegardlessPosition() { xpath.Append("//*"); } public static void AddAnyAttribute() { xpath.Append("[@*]"); } public static void Load(string filename) { xmlDoc.Load(filename); root = xmlDoc.DocumentElement; } public static XmlNodeList Commit(string commit=null) { XmlNodeList xn=null; if (commit != null) { xn= root.SelectNodes(commit); } else if (xpath.Length != 0) { xn= root.SelectNodes(XmlUtils.xpath.ToString()); xpath.Clear(); } return xn; } public void addElement(string path, string node_root, string node_name, string node_text, string att_name, string att_value) { Load(path); XmlNodeList nodeList = xmlDoc.SelectSingleNode(node_root).ChildNodes;//获取bookstore节点的所有子节点 //判断是否有节点,有节点就遍历所有子节点,看看有没有重复节点,没节点就添加一个新节点 if (nodeList.Count > 0) { foreach (XmlNode xn in nodeList)//遍历所有子节点 { XmlElement xe = (XmlElement)xn;//将子节点类型转换为XmlElement类型 if (xe.GetAttribute(att_name) != att_value) { XmlNode xmldocSelect = xmlDoc.SelectSingleNode(node_root); //选中根节点 XmlElement son_node = xmlDoc.CreateElement(node_name); //添加子节点 son_node.SetAttribute(att_name, att_value); //设置属性 son_node.InnerText = node_text; //添加节点文本 xmldocSelect.AppendChild(son_node); //添加子节点 xmlDoc.Save(path); //保存xml文件 break; } } } else { XmlNode xmldocSelect = xmlDoc.SelectSingleNode(node_root); //选中根节点 XmlElement son_node = xmlDoc.CreateElement(node_name); //添加子节点 son_node.SetAttribute(att_name, att_value); //设置属性 son_node.InnerText = node_text; //添加节点文本 xmldocSelect.AppendChild(son_node); //添加子节点 xmlDoc.Save(path); //保存xml文件 } } /// <summary> /// 修改节点的内容 /// </summary> /// <param name="path">xml文件的物理路径</param> /// <param name="node_root">根节点名称</param> /// <param name="new_text">节点的新内容</param> /// <param name="att_name">节点的属性名</param> /// <param name="att_value">节点的属性值</param> public void UpdateElement(string path, string node_root, string new_text, string att_name, string att_value) { Load(path); XmlNodeList nodeList = xmlDoc.SelectSingleNode(node_root).ChildNodes;//获取bookstore节点的所有子节点 foreach (XmlNode xn in nodeList)//遍历所有子节点 { XmlElement xe = (XmlElement)xn;//将子节点类型转换为XmlElement类型 if (xe.GetAttribute(att_name) == att_value) { xe.InnerText = new_text; //内容赋值 xmlDoc.Save(path);//保存 break; } } } /// <summary> /// 删除节点 /// </summary> /// <param name="path">xml文件的物理路径</param> /// <param name="node_root">根节点名称</param> /// <param name="att_name">节点的属性名</param> /// <param name="att_value">节点的属性值</param> public void deleteNode(string path, string node_root, string att_name, string att_value) { Load(path); XmlNodeList nodeList = xmlDoc.SelectSingleNode(node_root).ChildNodes; XmlNode root = xmlDoc.SelectSingleNode(node_root); foreach (XmlNode xn in nodeList) { XmlElement xe = (XmlElement)xn; if (xe.GetAttribute(att_name) == att_value) { //xe.RemoveAttribute("name");//删除name属性 xe.RemoveAll();//删除该节点的全部内容 root.RemoveChild(xe); xmlDoc.Save(path);//保存 break; } } } } }
最后说下自己的感悟:因为刚毕业,工作中的很多问题都没有接触过,虽然都很简单,但是要做出来还是要花一定时间的,所以D.S.Qiu觉得学一个新东西一定要彻底弄懂,以后才能事半功倍,还要记录一些学习过程中遇到的问题和解决问题的一些方法和心得。
如果您对D.S.Qiu有任何建议或意见可以在文章后面评论,或者发邮件(gd.s.qiu@gmail.com)交流,您的鼓励和支持是我前进的动力,希望能有更多更好的分享。