C#操作xml文件:DOM与Linq方式对比——创建、读取、查找、增加、删除、修改、替换、移动与复制到其他文件

3 篇文章 0 订阅

参考文章:在Visual C#中使用XML指南之读取XMLLINQ to XML 与DOM (C#)

一、DOM to XML 与 LINQ to XML

  在C#中,一般用三种方法来读取xml文件:
    (1)XmlDocument(DOM模式)
    (2)使用 XmlTextReader(流模式)
    (3)使用 Linq to Xml(Linq模式)
  前两种是在程序中访问并操作XML文件:
  DOM(文档对象模型):使用DOM的好处在于它允许编辑和更新XML文档,可以随机访问文档中的数据,可以使用XPath查询。但是,DOM的缺点在于它需要一次性的加载整个文档到内存中,对于大型的文档,这会造成资源问题。
  流模型:流模型很好地解决了这个问题,因为它对XML文件的访问采用的是流的概念,也就是说,任何时候在内存中只有当前节点,因此内存暂用少。但它是只读的,仅向前的,不能在文档中执行向后导航操作。
  第三种是利用C#的linq方法(C#的查询功能)来操作xml文件,代码少易于理解。
  本文主要比较DOM方法与Linq方法:DOM to XML方法中,是从下至上生成 XML 树;即先创建文档,然后创建元素,再将元素添加到文档。这种编码方式不会提供很多有关 XML 树结构的可视信息。LINQ to XML 也支持用此方法创建 XML 树,但也支持另一种方法,即函数构造。 函数构造使用 XElement 和 XAttribute 构造函数生成 XML 树,用于构造 XML 树的代码可显示基础 XML 的结构。

二、功能对比

  以下方法,DOM to XML在类XmlDOM中,LINQ to XML在类XmlLinq中。

(1) DOM to XML
//xml DOM
using System.Xml;
//xml file
using System.IO;
class XmlDOM
{}
(2) LINQ to XML
//xml linq
using System.Xml.Linq;
//xml file
using System.IO;
class XmlLinq
{}

1、创建文件
(1) DOM to XML
        /// <summary>
        /// 创建文件
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        public void CreateXml(string xmlfile)
        {
            if (!File.Exists(xmlfile))
            {
                //实例化XmlDocument对象
                XmlDocument xd = new XmlDocument();
                //xml文件的头文件声明
                XmlDeclaration declare = xd.CreateXmlDeclaration("1.0", "utf-8", "yes");
                xd.AppendChild(declare);
                //创建根节点
                XmlElement school = xd.CreateElement("school");
                school.SetAttribute("name", "new school");
                //创建一级子节点
                XmlElement fschool = xd.CreateElement("class");
                fschool.SetAttribute("number", "01");
                //创建二级第一个子节点
                XmlElement fclass = xd.CreateElement("student");
                fclass.SetAttribute("id", "01");
                fclass.SetAttribute("name", "Dan");
                fclass.SetAttribute("age", "18");
                //创建二级第二个子节点
                XmlElement sclass = xd.CreateElement("student");
                sclass.SetAttribute("id", "02");
                sclass.SetAttribute("name", "Tom");
                sclass.SetAttribute("age", "18");
                //添加节点到父节点,添加根节点到对象
                xd.AppendChild(school);
                school.AppendChild(fschool);
                fschool.AppendChild(fclass);
                fschool.AppendChild(sclass);
                xd.Save(xmlfile);
            }
        }
(2) LINQ to XML
        /// <summary>
        /// 创建文件
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        public void CreateXml(string xmlfile)
        {
            if (!File.Exists(xmlfile))
            {

                //方法一 按照DOM方式添加
                //实例化XDocument对象 
                XDocument xdoc = new XDocument();
                //创建根节点
                XElement root = new XElement("school");
                //创建一级子节点
                XElement fchild = new XElement("class");
                fchild.SetAttributeValue("number", "01");
                //创建二级第一个子节点
                XElement schild1 = new XElement("student");
                schild1.SetAttributeValue("id", "01");
                schild1.SetAttributeValue("name", "Dan");
                schild1.SetAttributeValue("age", "18");
                //创建二级第二个子节点
                XElement schild2 = new XElement("student");
                schild2.SetAttributeValue("id", "02");
                schild2.SetAttributeValue("name", "Tom");
                schild2.SetAttributeValue("age", "18");
                //添加节点到父节点,添加根节点到对象
                fchild.Add(schild1);
                fchild.Add(schild2);
                root.Add(fchild);
                xdoc.Add(root);

                //使用XML的保存会自动在xml文件开始添加:<?xml version="1.0" encoding="utf-8"?>
                xdoc.Save("school.xml");

                //方法二 按照xml文件树状格式添加
                XDocument xd = new XDocument(
                    new XElement("school", new XAttribute("name", "new school"),
                        new XElement("class", new XAttribute("number", "01"),
                            new XElement("student", new XAttribute("id", "01"), new XAttribute("name", "Dan"), new XAttribute("age", "18")),
                            new XElement("student", new XAttribute("id", "02"), new XAttribute("name", "Tom"), new XAttribute("age", "18"))
                        )
                    )
                );
                //使用XML的保存会自动在xml文件开始添加:<?xml version="1.0" encoding="utf-8"?>
                xd.Save(xmlfile);
            }
        }

2、读取文件
(2) LINQ to XML
        /// <summary>
        /// 读取文件
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        public void ReadXml(string xmlfile)
        {
            if (File.Exists(xmlfile))
            {
                //省略了判定xml文件存在
                XDocument xd = new XDocument();
                xd = XDocument.Load(xmlfile);
                XElement root = xd.Root;
                //获取根节点下所有子节点
                IEnumerable<XElement> xe = root.Elements();
                foreach (XElement fxe in xe)
                {
                    foreach (XElement sxe in fxe.Elements())
                    {
                        Console.WriteLine(sxe.Name);
                        Console.WriteLine(sxe.Attribute("id").Value);
                    }
                }
            }
            Console.ReadLine();
        }

3、在文件中查找
(1) DOM to XML
        /// <summary>
        /// 在文件中查找
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        /// <param name="nodename">节点属性名称</param>
        public void SearchInXml(string xmlfile, string nodename)
        {
            if (File.Exists(xmlfile))
            {
                XmlDocument xd = new XmlDocument();
                xd.Load(xmlfile);
                //查找固定名称 节点名要从根节点开始写
                XmlNode node_name = xd.DocumentElement.SelectSingleNode("/school/class/student[@id='" + nodename + "']");
                XmlElement ele_name = (XmlElement)node_name;
                //查找固定位置
                XmlNode node_position = xd.DocumentElement.SelectSingleNode("/school/class/student[position()=2]");
                XmlElement ele_position = (XmlElement)node_position;


                //保存到其他xml中测试上面的结果
                CopyToOtherXmlNode("dom.xml", "dom1.xml", node_name);
                CopyToOtherXmlNode("dom.xml", "dom1.xml", ele_name);
                CopyToOtherXmlNode("dom.xml", "dom1.xml", node_position);
                CopyToOtherXmlNode("dom.xml", "dom1.xml", ele_position);
            }
        }
(2) LINQ to XML
        /// <summary>
        /// 在文件中查找
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        public void SearchInXml(string xmlfile)
        {
            if (File.Exists(xmlfile))
            {
                XDocument xd = new XDocument();
                xd = XDocument.Load(xmlfile);

                //获取所有节点
                IEnumerable<XNode> nodes = xd.DescendantNodes();
                //找到单个节点
                IEnumerable<XElement> node = xd.Descendants("class");
                //找到特点节点 子节点有element且其属性id值为01
                IEnumerable<XElement> element = xd.Descendants("class")
                    .Where(p => (string)p.Element("student").Attribute("id").Value == "01");
                //如果只取一个,可以用下面这个方法 First表示枚举中的第一个
                XElement element_first = xd.Descendants("class")
                    .Where(p => (string)p.Element("student").Attribute("id").Value == "01").First();

                //把结果保存到单独的xml文件以进行观察
                XDocument xd_nodes = new XDocument(
                    new XElement("school",
                       nodes
                     )
                );
                xd_nodes.Save("nodes.xml");

                XDocument xd_node = new XDocument(
                    new XElement("school",
                       node
                     )
                );
                xd_node.Save("node.xml");

                XDocument xd_element = new XDocument(
                    new XElement("school",
                       element
                     )
                );
                xd_element.Save("element.xml");


                //获取值
                var selement = xd.Descendants("class")
                    .Select(p => new { age = p.Element("student") }); //获得节点

                var welement = xd.Descendants("class")
                    .Where(p => p.Element("student").Attribute("name").Value.Contains("D"))  //条件筛选 寻找student:其name属性的值包含有字母D
                    .Select(p => new { age = p.Element("student") }); //获得节点

                //输出结果
                string strs = "";
                foreach (var a in selement)
                {
                    strs += a.age + "\r\n";
                }

                Console.Write(strs);

                string strw = "";
                foreach (var a in selement)
                {
                    strw += a.age + "\r\n";
                }

                Console.Write(strw);

                Console.Read();
            }
        }

4、追加节点、属性和内容
(1) DOM to XML
        /// <summary>
        /// 追加节点
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        /// <param name="nodename">节点属性名称</param>
        public void AppendNode(string xmlfile, string nodename)
        {
            if (File.Exists(xmlfile))
            {
                XmlDocument xd = new XmlDocument();
                xd.Load(xmlfile);
                
                XmlNode node = xd.DocumentElement.SelectSingleNode("/school/class/student[@id='" + nodename + "']");
                
                //添加节点
                XmlElement ele = xd.CreateElement("sport");
                ele.InnerText = "football";
                //InsertAfter为在node后加,InsertBefore为在node前加,这两种增加后的节点与node同级
                //AppendChild为在node的最后一个子节点后再追加一个子节点,这种增加后的节点为node的子节点
                node.AppendChild(ele);
               
                //添加属性
                XmlElement nodee = (XmlElement)node;
                nodee.SetAttribute("gender", "male");

                xd.Save(xmlfile);
            }
        }
(2) LINQ to XML
        /// <summary>
        /// 追加节点、属性和内容
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        public void AppendNode(string xmlfile)
        {
            if (File.Exists(xmlfile))
            {
                XDocument xd = new XDocument();
                xd = XDocument.Load(xmlfile);

                XElement parent_class = xd.Descendants("class")
                    .Where(p => (string)p.Element("student").Attribute("id").Value == "01").First();
                XElement ele = new XElement("student", new XAttribute("id", "03"), "Sue");
                parent_class.Add(ele);
                xd.Save(xmlfile);
            }
        }

5、删除节点
(1) DOM to XML
        /// <summary>
        /// 删除节点
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        /// <param name="nodename">节点属性名称</param>
        public void DeleteNode(string xmlfile, string nodename)
        {
            if (File.Exists(xmlfile))
            {
                XmlDocument xd = new XmlDocument();
                xd.Load(xmlfile);

                XmlNode node = xd.DocumentElement.SelectSingleNode("/school/class/student[@id='" + nodename + "']");
                
                xd.DocumentElement.FirstChild.RemoveChild(node);
                xd.Save(xmlfile);
            }
        }
(2) LINQ to XML
        /// <summary>
        /// 删除节点
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        public void DeleteNode(string xmlfile)
        {
            if (File.Exists(xmlfile))
            {
                XDocument xd = new XDocument();
                xd = XDocument.Load(xmlfile);

                //删除节点 全部没有了
                xd.Descendants("class")
                    .Where(p => (string)p.Element("student").Attribute("id").Value == "01").First()
                    .Remove();
                //删除节点内容 只剩下节点名
                xd.Descendants("class")
                    .Where(p => (string)p.Element("student").Attribute("id").Value == "01").First()
                    .RemoveAll();
                //删除节点属性 内容还在
                xd.Descendants("class")
                    .Where(p => (string)p.Element("student").Attribute("id").Value == "01").First()
                    .RemoveAttributes();
                //删除节点内容 只剩下节点名和属性
                xd.Descendants("class")
                    .Where(p => (string)p.Element("student").Attribute("id").Value == "01").First()
                    .RemoveNodes();

                xd.Save(xmlfile);
            }
        }

6、修改节点内容和属性
(1) DOM to XML
        /// <summary>
        /// 修改节点
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        /// <param name="nodename">节点属性名称</param>
        public void ModifyNode(string xmlfile, string nodename)
        {
            if (File.Exists(xmlfile))
            {
                XmlDocument xd = new XmlDocument();
                xd.Load(xmlfile);

                XmlNode node = xd.DocumentElement.SelectSingleNode("/school/class/student[@id='" + nodename + "']");

                node.InnerText = "node text";
                node.Attributes["age"].Value = "19";
                xd.Save(xmlfile);
            }
        }
(2) LINQ to XML
        /// <summary>
        /// 修改节点内容和属性
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        public void ModifyNode(string xmlfile)
        {
            if (File.Exists(xmlfile))
            {
                XDocument xd = new XDocument();
                xd = XDocument.Load(xmlfile);

                XElement ele = xd.Descendants("class")
                     .Where(p => (string)p.Element("student").Attribute("id").Value == "01").First();
                ele.Value = "This is a class";
                ele.Attribute("number").Value = "1";

                xd.Save(xmlfile);
            }
        }

7、替换节点或内容
(1) DOM to XML
        /// <summary>
        /// 替换节点
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        /// <param name="nodename">节点属性名称</param>
        public void ReplaceNode(string xmlfile, string nodename)
        {
            if (File.Exists(xmlfile))
            {
                XmlDocument xd = new XmlDocument();
                xd.Load(xmlfile);
                //如果用同一文件的节点替换,相当于删除被替换节点,将替换节点从原位置移动到被替换节点位置
                XmlNode node = xd.DocumentElement.SelectSingleNode("/school/class/student[@id='" + nodename + "']");
                XmlNode node2 = xd.DocumentElement.SelectSingleNode("/school/class/student[@id='02']");
                xd.DocumentElement.FirstChild.ReplaceChild(node2, node);
                xd.Save(xmlfile);
            }
        }
(2) LINQ to XML
        /// <summary>
        /// 替换节点或内容
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        public void ReplaceNode(string xmlfile)
        {
            if (File.Exists(xmlfile))
            {
                XDocument xd = new XDocument();
                xd = XDocument.Load(xmlfile);
                
                //将元素的子元素替换为新的内容 节点名仍保留,其他全部被替换
                XElement ele = xd.Descendants("class")
                   .Where(p => (string)p.Element("student").Attribute("id").Value == "01").First();
                xd.Descendants("class")
                        .Where(p => (string)p.Element("student").Attribute("id").Value == "01").Last()
                        .ReplaceAll(ele);
                //将元素属性替换为文本 元素名和子节点保留
                xd.Descendants("class")
                        .Where(p => (string)p.Element("student").Attribute("id").Value == "01").Last()
                        .ReplaceAttributes("123");
                //将元素子节点替换为新的内容 元素名和属性保留
                xd.Descendants("class")
                        .Where(p => (string)p.Element("student").Attribute("id").Value == "01").Last()
                        .ReplaceNodes("123");
                //将元素替换为新的内容 全都没有了
                xd.Descendants("class")
                        .Where(p => (string)p.Element("student").Attribute("id").Value == "01").Last()
                        .ReplaceWith("123");

                xd.Save(xmlfile);
            }
        }

8、在当前文件中移动或复制节点
(1) DOM to XML
        /// <summary>
        /// 在当前文件中移动或复制节点
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
         /// <param name="nodename">节点属性名称</param>
        public void MoveOrCopyNode(string xmlfile, string nodename)
        {
            if (File.Exists(xmlfile))
            {
                XmlDocument xd = new XmlDocument();
                xd.Load(xmlfile);

                XmlNode node = xd.DocumentElement.SelectSingleNode("/school/class/student[@id='" + nodename + "']");
                在C#中从一个结构到另一个相同的结构,必须先取出节点然后使用import
                如从一个xml的节点到另一个xml需要用ImportNode
                如从一个databale的行到另一个databale需要用ImportRow
                XmlNode markNode = xd.ImportNode(node, true);
                //下面两句话可以用上面的ReplaceNode方法
                //如果是移动节点则取消下面这句话的注释:删除原节点  
                //xd.DocumentElement.FirstChild.RemoveChild(node);
                xd.DocumentElement.AppendChild(markNode);
                xd.Save(xmlfile);
            }
        }
(2) LINQ to XML
        /// <summary>
        /// 在当前文件中移动或复制节点
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        public void MoveOrCopyNode(string xmlfile)
        {
            if (File.Exists(xmlfile))
            {
                XDocument xd = new XDocument();
                xd = XDocument.Load(xmlfile);
                //找出节点然后添加 如果是移动还要删除原来位置
                IEnumerable<XElement> ele = xd.Descendants("class")
                  .Where(p => (string)p.Element("student").Attribute("id").Value == "01");
                ele.ElementAt(0).Add(ele.ElementAt(1));
                xd.Save(xmlfile);
                
            }
        }

9、将节点复制到其他xml文件
(1) DOM to XML
        /// <summary>
        /// 将节点复制到其他xml文件
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        /// <param name="desfile">包含路径和扩展名的目标文件名</param>
        /// <param name="movenode">要移动的节点</param>
        public void CopyToOtherXmlNode(string xmlfile, string desfile, XmlNode movenode)
        {
            if (File.Exists(xmlfile) && File.Exists(desfile))
            {
                XmlDocument xd = new XmlDocument();
                xd.Load(xmlfile);

                XmlDocument xm = new XmlDocument();
                xm.Load(desfile);

                在C#中从一个结构到另一个相同的结构,必须先取出节点然后使用import
                如从一个xml的节点到另一个xml需要用ImportNode
                如从一个databale的行到另一个databale需要用ImportRow
                XmlNode markNode = xm.ImportNode(movenode, true);
                xm.DocumentElement.AppendChild(markNode);
                xm.Save(desfile);
            }
        }
(2) LINQ to XML
        /// <summary>
        /// 将节点复制到其他xml文件
        /// </summary>
        /// <param name="xmlfile">包含路径和扩展名的文件名</param>
        /// <param name="xmlfile2">要添加节点的文件的文件名</param>
        public void CopyToOtherXmlNode(string xmlfile, string xmlfile2)
        {
            if (File.Exists(xmlfile))
            {
                XDocument xd = new XDocument();
                xd = XDocument.Load(xmlfile);

                IEnumerable<XElement> node = xd.Descendants("class");
                //把结果保存到单独的xml文件以进行观察
                XDocument xd_node = new XDocument(
                    new XElement("school",
                       node
                     )
                );
                xd_node.Save("node.xml");
				
				//把结果保存到已存在的xml文件的根结点末尾,作为根结点最后一个子节点
				XDocument xd2 = new XDocument();
                xd2 = XDocument.Load(xmlfile2);
                xd2.Root.Add(node);
            }
        }

下载完整代码learning-everything/csharp/CsharpFunction/XmlDOM.cslearning-everything/csharp/CsharpFunction/XmlLinq.cs

  • 9
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值