欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C# LINQ学习笔记五:LINQ to XML

程序员文章站 2023-10-29 10:27:58
本笔记摘抄自:https://www.cnblogs.com/yaozhenfa/p/CSharp_Linq_For_Xml.html,记录一下学习过程以备后续查用。 一、生成xml 1.1创建简单的xml /// /// CreateXml类 /// pu ......

    本笔记摘抄自:https://www.cnblogs.com/yaozhenfa/p/csharp_linq_for_xml.html,记录一下学习过程以备后续查用。

    一、生成xml

    1.1创建简单的xml

    /// <summary>
    /// createxml类
    /// </summary>
    public class createxml
    {
        /// <summary>
        /// 返回xml文件路径
        /// </summary>
        public string path
        {
            get
            {
                string path = @"..\..\linqtoxml.xml";
                return path;
            }
        }

        /// <summary>
        /// 创建简单的xml并保存
        /// </summary>
        public void createelement()
        {
            xdocument xdoc = new xdocument
                (
                    //创建一个xml文档
                    //设置该xml的版本为1.0,采用utf - 8编码,后面的yes表示该xml是独立的。
                    new xdeclaration("1.0", "utf-8", "yes"),
                    //开始创建每个节点的,首先是root节点,然后在root节点中添加两个item节点。
                    new xelement
                    (
                        "root",
                        new xelement("item", "1"),
                        new xelement("item", "2")
                    )
                );
            xdoc.save(path);
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region 创建简单的xml
            createxml xml = new createxml();
            xml.createelement();
            #endregion
        }
    }

    最终生成的xml如下所示:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<root>
  <item>1</item>
  <item>2</item>
</root>

    1.2创建xml注释

    当xml有很多项时,我们就需要利用注释加以区别,通过linq to xml我们一样可以在其中添加注释。

    /// <summary>
    /// createxml类
    /// </summary>
    public class createxml
    {
        /// <summary>
        /// 返回xml文件路径
        /// </summary>
        public string path
        {
            get
            {
                string path = @"..\..\linqtoxml.xml";
                return path;
            }
        }

        /// <summary>
        /// 创建xml注释
        /// </summary>
        public void createcomment()
        {
            xdocument xdoc = new xdocument
                (
                    new xdeclaration("1.0", "utf-8", "yes"),
                    new xcomment("这里是注释"),
                    new xelement
                        (
                            "root",
                            new xelement("item", "1"),
                            new xelement("item", "2")
                        )
                );
            xdoc.save(path);
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 创建xml注释
            createxml xml = new createxml();
            xml.createcomment();
            #endregion
        }
    }

    最终生成的xml如下所示:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!--这里是注释-->
<root>
  <item>1</item>
  <item>2</item>
</root>

    1.3根据对象创建xml

    很多时候我们都会将数组之类的类型转换成xml以便保存进永久性存储介质中。

    /// <summary>
    /// createxml类
    /// </summary>
    public class createxml
    {
        /// <summary>
        /// 返回xml文件路径
        /// </summary>
        public string path
        {
            get
            {
                string path = @"..\..\linqtoxml.xml";
                return path;
            }
        }

        /// <summary>
        /// 根据对象创建xml并保存
        /// </summary>
        public void createelementbyobjects()
        {
            var objs = enumerable.range(1, 6);
            xelement xe = new xelement
                (
                    "root",
                    from obj in objs
                    select new xelement("item", obj.tostring())
                );
            xe.save(path);
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 根据对象创建xml
            createxml xml = new createxml();
            xml.createelementbyobjects();
            #endregion
        }
    }

    最终生成的xml如下所示:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <item>1</item>
  <item>2</item>
  <item>3</item>
  <item>4</item>
  <item>5</item>
  <item>6</item>
</root>

    1.4创建xml属性

    有时我们不想创建新的子项去保存数据,而是使用属性的方式去保存。理所应当,linq to xml一样也支持这个功能,下面我们可以通过简单的语句去

实现它。

    /// <summary>
    /// createxml类
    /// </summary>
    public class createxml
    {
        /// <summary>
        /// 返回xml文件路径
        /// </summary>
        public string path
        {
            get
            {
                string path = @"..\..\linqtoxml.xml";
                return path;
            }
        }

        /// <summary>
        /// 创建xml属性
        /// </summary>
        public void createattribute()
        {
            xattribute xa = new xattribute("v2", "2");
            xelement xe = new xelement
                (
                    "root",
                    new xelement
                        (
                            "item",
                            new xattribute("v1", "1"),
                            xa
                        )
                );
            xe.save(path);
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 创建xml属性
            createxml xml = new createxml();
            xml.createattribute();
            #endregion
        }
    }

    最终生成的xml如下所示:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <item v1="1" v2="2" />
</root>

    1.5创建xml命名空间

    对于一些企业级的xml格式,会非常的严格,特别是在同一个xml中可能会出现重复的项,但是我们又想区分开来,这个时候我们可以利用命名空间将

他们分开(跟c#中的命名空间类似)。

    /// <summary>
    /// createxml类
    /// </summary>
    public class createxml
    {
        /// <summary>
        /// 返回xml文件路径
        /// </summary>
        public string path
        {
            get
            {
                string path = @"..\..\linqtoxml.xml";
                return path;
            }
        }

        /// <summary>
        /// 创建xml命名空间
        /// </summary>
        public void createnamespace()
        {
            xelement xe = new xelement
                (
                    "{http://www.xamarin-cn.com/}root",
                    new xelement("item", "1"),
                    new xelement("{http://www.baidu.com/}item", 2)
                );
            xe.save(path);
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 创建xml命名空间
            createxml xml = new createxml();
            xml.createnamespace();
            #endregion
        }
    }

    最终生成的xml如下所示:

<?xml version="1.0" encoding="utf-8"?>
<root xmlns="http://www.xamarin-cn.com/">
  <item xmlns="">1</item>
  <item xmlns="http://www.baidu.com/">2</item>
</root>

    从这个结果中我们可以看到对应的属性中有了xmlns属性,并且值就是我们赋给它的命名空间。

    二、查询并修改xml

    linq to xml不仅创建xml简单,在查询、编辑和删除方面也一样是非常方便的。

    创建一个xmlreadwrite.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <item v1="1" v2="2">item1</item>
  <item v1="1" v2="2">item2</item>
</root>

    2.1读取xml文件

    /// <summary>
    /// queryxml类
    /// </summary>
    public class queryxml
    {
        /// <summary>
        /// 返回xml文件路径
        /// </summary>
        public string path
        {
            get
            {
                string path = @"..\..\xmlreadwrite.xml";
                return path;
            }
        }

        /// <summary>
        /// 读取xml文件
        /// </summary>
        public void queryelementbyfile()
        {
            xelement xe = xelement.load(path);
            xelement xe1 = xe.element("item");
            console.write(xe1.value.trim());
            console.readkey();
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 读取xml文件
            queryxml xml = new queryxml();
            xml.queryelementbyfile();
            #endregion
        }
    }

    运行结果如下:

C# LINQ学习笔记五:LINQ to XML

    上面的示例,我们利用xelement的静态方法load读取指定路径下的xml文件,同时还获取了该xml文件的第一个item的值并输出。

    2.2在xml指定节点前后添加新节点

    /// <summary>
    /// queryxml类
    /// </summary>
    public class queryxml
    {
        /// <summary>
        /// 返回xml文件路径
        /// </summary>
        public string path
        {
            get
            {
                string path = @"..\..\xmlreadwrite.xml";
                return path;
            }
        }

        /// <summary>
        /// 在xml指定节点前后添加新节点
        /// </summary>
        public void addelementbeforeandafter()
        {
            xelement xe = xelement.load(path);
            var item = (from t in xe.elements("item")
                        where t.value.equals("item2")
                        select t).singleordefault();
            if (item != null)
            {
                xelement bxe = new xelement("item", "itemb");
                xelement axe = new xelement("item", "itema");
                item.addbeforeself(bxe);
                item.addafterself(axe);
                xe.save(path);
            }
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 在xml指定节点前后添加新节点
            queryxml xml = new queryxml();
            xml.addelementbeforeandafter();
            #endregion
        }
    }

    最终生成的xml如下所示:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <item v1="1" v2="2">item1</item>
  <item>itemb</item>
  <item v1="1" v2="2">item2</item>
  <item>itema</item>
</root>

    2.3添加属性到xml节点中

    我们已经可以动态的添加节点,但是创建的时候不仅仅可以创建节点,并且还能创建属性,下面我们可以通过setattributevalue去添加新的属性或者

修改现有属性。

    /// <summary>
    /// queryxml类
    /// </summary>
    public class queryxml
    {
        /// <summary>
        /// 返回xml文件路径
        /// </summary>
        public string path
        {
            get
            {
                string path = @"..\..\xmlreadwrite.xml";
                return path;
            }
        }

        /// <summary>
        /// 添加属性到xml节点中
        /// </summary>
        public void addattributetoelement()
        {
            xelement xe = xelement.parse(@"<?xml version='1.0' encoding='utf-8'?><root>
                <item v1='1' v2='2'>item1</item><item v1='1' v2='2'>item2</item></root>");
            var item = (from t in xe.elements("item")
                        where t.value.equals("item2")
                        select t).singleordefault();
            item.setattributevalue("v3", "3");
            xe.save(path);
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 添加属性到xml节点中
            queryxml xml = new queryxml();
            xml.addattributetoelement();
            #endregion
        }
    }

    最终生成的xml如下所示:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <item v1="1" v2="2">item1</item>
  <item v1="1" v2="2" v3="3">item2</item>
</root>

    2.4添加注释到xml指定节点前后

    这里的语法基本跟【在xml指定节点前后添加新节点】是相似的,只是读取xml的方式不同。

    /// <summary>
    /// queryxml类
    /// </summary>
    public class queryxml
    {
        /// <summary>
        /// 返回xml文件路径
        /// </summary>
        public string path
        {
            get
            {
                string path = @"..\..\xmlreadwrite.xml";
                return path;
            }
        }

        /// <summary>
        /// 添加注释到xml指定节点前后
        /// </summary>
        public void addcommentbeforeandafter()
        {
            textreader tr = new stringreader(@"<?xml version='1.0' encoding='utf-8'?><root>
                <item v1='1' v2='2'>item1</item><item v1='1' v2='2' v3='3'>item2</item></root>");
            xelement xe = xelement.load(tr);
            var item = (from t in xe.elements("item")
                        where t.value.equals("item1")
                        select t).firstordefault();
            if (item != null)
            {
                xcomment bcom = new xcomment("前面的注释");
                xcomment acom = new xcomment("后面的注释");
                item.addbeforeself(bcom);
                item.addafterself(acom);
            }
            tr.close();
            xe.save(path);
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 添加注释到xml指定节点前后
            queryxml xml = new queryxml();
            xml.addcommentbeforeandafter();
            #endregion
        }
    }

    最终生成的xml如下所示:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <!--前面的注释-->
  <item v1="1" v2="2">item1</item>
  <!--后面的注释-->
  <item v1="1" v2="2" v3="3">item2</item>
</root>

    2.5替换xml指定节点

    修改节点的值通过setvalue即可做到,但是有时涉及到子节点,而我们想一次性全部替换掉,那么我们就需要使用replacewith

    /// <summary>
    /// queryxml类
    /// </summary>
    public class queryxml
    {
        /// <summary>
        /// 返回xml文件路径
        /// </summary>
        public string path
        {
            get
            {
                string path = @"..\..\xmlreadwrite.xml";
                return path;
            }
        }

        /// <summary>
        /// 替换xml指定节点
        /// </summary>
        public void replaceelement()
        {
            xelement xe = xelement.load(path);
            var item = (from t in xe.elements("item")
                        where t.value.equals("item2")
                        select t).firstordefault();
            if (item != null)
            {
                item.replacewith(new xelement("item", "item3"));
            }
            xe.save(path);
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 替换xml指定节点
            queryxml xml = new queryxml();
            xml.replaceelement();
            #endregion
        }
    }

    最终生成的xml如下所示:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <!--前面的注释-->
  <item v1="1" v2="2">item1</item>
  <!--后面的注释-->
  <item>item3</item>
</root>

    2.6删除xml指定属性

    前面我们介绍了创建、修改和添加属性,但是还没有介绍如何删除指定的属性,下面我们就通过一个简单的实例来演示。

    /// <summary>
    /// queryxml类
    /// </summary>
    public class queryxml
    {
        /// <summary>
        /// 返回xml文件路径
        /// </summary>
        public string path
        {
            get
            {
                string path = @"..\..\xmlreadwrite.xml";
                return path;
            }
        }

        /// <summary>
        /// 删除xml指定属性
        /// </summary>
        public void removeattribute()
        {
            xelement xe = xelement.load(path);
            var item = (from t in xe.elements("item")
                        where t.value.equals("item1")
                        select t).firstordefault().attribute("v2");
            if (item != null)
            {
                item.remove();
            }
            xe.save(path);
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 删除xml指定属性
            queryxml xml = new queryxml();
            xml.removeattribute();
            #endregion
        }
    }

    最终生成的xml如下所示:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <!--前面的注释-->
  <item v1="1">item1</item>
  <!--后面的注释-->
  <item>item3</item>
</root>

    2.7删除xml指定节点

    既然上面已经可以删除属性,自然也少不了删除属性。

    /// <summary>
    /// queryxml类
    /// </summary>
    public class queryxml
    {
        /// <summary>
        /// 返回xml文件路径
        /// </summary>
        public string path
        {
            get
            {
                string path = @"..\..\xmlreadwrite.xml";
                return path;
            }
        }

        /// <summary>
        /// 删除xml指定节点
        /// </summary>
        public void removeelement()
        {
            xelement xe = xelement.load(path);
            var item = (from t in xe.elements("item")
                        where t.value.equals("item3")
                        select t).firstordefault();
            if (item != null)
            {
                item.remove();
            }
            xe.save(path);
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 删除xml指定节点
            queryxml xml = new queryxml();
            xml.removeelement();
            #endregion
        }
    }

    最终生成的xml如下所示:

<?xml version="1.0" encoding="utf-8"?>
<root>
  <!--前面的注释-->
  <item v1="1">item1</item>
  <!--后面的注释-->
</root>

    三、按节点关系查询

    上面的查询都是通过相关的条件进行查询,但是我们有时仅仅只需要通过之间的关系即可,这样反而可以避免很多的代码,当然稍加探索可以发现其

xelement都提供给我们了。

    创建一个structure.xml文件:

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <item>
    <subitem1>
      1
    </subitem1>
    <subitem>
      <child>
        sss
      </child>
    </subitem>
    <subitem2>
      2
    </subitem2>
  </item>
</root>

    3.1显示xml指定节点的所有父节点

    通过上面的xml文件,我们清晰的看出xml是具有结构性的,彼此之间都存在关系,而现在我们需要显示某个节点的父级节点的名称。

    /// <summary>
    /// structurexml类
    /// </summary>
    public class structurexml
    {
        public string path
        {
            get
            {
                string path = string.format(@"..\..\structure.xml");
                return path;
            }
        }

        /// <summary>
        /// 显示xml指定节点的所有父节点
        /// </summary>
        public void showallparentelement()
        {
            xelement xe = xelement.load(path);
            var item = (from t in xe.descendants("child")
                        select t).firstordefault();
            if (item != null)
            {
                console.writeline("----------------------------");
                console.writeline($"{item.name}的向上父节点有:");
                foreach (var upper in item.ancestors())
                {
                    console.writeline(upper.name);
                }
                console.writeline("----------------------------");
                console.writeline($"{item.name}及向上父节点有:");
                foreach (var selfandupper in item.ancestorsandself())
                {
                    console.writeline(selfandupper.name);
                }
                console.read();
            }
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 显示xml指定节点的所有父节点
            structurexml xml = new structurexml();
            xml.showallparentelement();
            #endregion
        }
    }

    运行结果如下:

C# LINQ学习笔记五:LINQ to XML

    3.2显示xml指定节点的所有子节点

    我们不仅仅可以输出一个节点的所有父级节点,同样也可以输出一个节点的所有子节点。

    /// <summary>
    /// structurexml类
    /// </summary>
    public class structurexml
    {
        public string path
        {
            get
            {
                string path = string.format(@"..\..\structure.xml");
                return path;
            }
        }

        /// <summary>
        /// 显示xml指定节点的所有子节点
        /// </summary>
        public void showallchildelement()
        {
            xelement xe = xelement.load(path);
            console.writeline("----------------------------");
            foreach (var sub in xe.descendants())
            {
                console.writeline(sub.name);
            }
            console.writeline("----------------------------");
            foreach (var sub in xe.descendantsandself())
            {
                console.writeline(sub.name);
            }
            console.readkey();
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 显示xml指定节点的所有子节点
            structurexml xml = new structurexml();
            xml.showallchildelement();
            #endregion
        }
    }

    运行结果如下:

C# LINQ学习笔记五:LINQ to XML

    3.3显示xml同级节点之前的节点

    既然有了父子关系,当然也少不了同级关系,首先我们先显示同级节点之前的节点。

    /// <summary>
    /// structurexml类
    /// </summary>
    public class structurexml
    {
        public string path
        {
            get
            {
                string path = string.format(@"..\..\structure.xml");
                return path;
            }
        }

        /// <summary>
        /// 显示xml同级节点之前的节点
        /// </summary>
        public void showprevelement()
        {
            xelement xe = xelement.load(path);
            var item = (from t in xe.descendants("subitem2")
                        select t).firstordefault();
            if (item != null)
            {
                console.writeline($"与{item.name}同级的前节点有:");
                foreach (var sub in item.elementsbeforeself())
                {
                    console.writeline(sub.name);
                }
            }
            console.read();
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 显示xml同级节点之前的节点
            structurexml xml = new structurexml();
            xml.showprevelement();
            #endregion
        }
    }

    运行结果如下:

C# LINQ学习笔记五:LINQ to XML

    3.4显示xml同级节点之后的节点

    /// <summary>
    /// structurexml类
    /// </summary>
    public class structurexml
    {
        public string path
        {
            get
            {
                string path = string.format(@"..\..\structure.xml");
                return path;
            }
        }

        /// <summary>
        /// 显示xml同级节点之后的节点
        /// </summary>
        public void shownextelement()
        {
            xelement xe = xelement.load(path);
            var item = (from t in xe.descendants("subitem1")
                        select t).firstordefault();
            if (item != null)
            {
                console.writeline($"与{item.name}同级的后节点有:");
                foreach (var sub in item.elementsafterself())
                {
                    console.writeline(sub.name);
                }
            }
            console.read();
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 显示xml同级节点之后的节点
            structurexml xml = new structurexml();
            xml.shownextelement();
            #endregion
        }
    }

    运行结果如下:

C# LINQ学习笔记五:LINQ to XML

    四、监听xml事件

    你可能会疑惑xml为什么还要监听?其实这样是有意义的,比如你要根据某个节点的值作为依赖,那么你就要监听这个节点,如果这个节点发生改变

的时候,你才可以及时的作出反应。但是xml的事件监听有一个特点,跟浏览器中的dom事件类似,监听父节点同样也可以监听的到它的子节点的事件。

    下面我们通过一个简单的示例来说明:

    /// <summary>
    /// eventxml类
    /// </summary>
    public static class eventxml
    {
        public static void bindchangeing()
        {
            xelement xe = new xelement("root");
            xe.changing += xelement_changing;
            xe.changed += xelement_changed;
            //添加元素
            xe.add(new xelement("item", "1"));
            var item = xe.element("item");
            //替换元素
            item.replacewith(new xelement("item", "2"));
            //删除元素
            item = xe.element("item");
            item.remove();
            //读取结果
            console.read();
        }

        static void xelement_changing(object sender, xobjectchangeeventargs e)
        {
            xelement xe = sender as xelement;
            console.writeline($"{xe.name}正在进行{e.objectchange}操作中,sender={sender.tostring()}。");
        }

        static void xelement_changed(object sender, xobjectchangeeventargs e)
        {
            xelement xe = sender as xelement;
            console.writeline($"{xe.name}已完成{e.objectchange}操作,sender={sender.tostring()}。\n");
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 监听xml事件
            eventxml.bindchangeing();
            #endregion
        }
    }

    运行结果如下:

C# LINQ学习笔记五:LINQ to XML

    五、处理xml流

    在实际的商业化的开发中,xml不可能仅仅保存这么点数据,有可能保存着非常多的数据。假如我们还是按照以往的方式,就会将xml全部读取进内

存,这样会占用非常多的内存从而影响系统的性能。针对这种情况我们需要使用流的方式去处理xml,因为流会按照我们的顺序读取部分xml进内存,

并不会将所有xml都读取到内存中。

    创建一个stream.xml文件:

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <subitem>1</subitem>
  <subitem>1</subitem>
  <subitem>1</subitem>
  <item>a</item>
  <subitem>1</subitem>
  <item>b</item>
</root>

    这里我们通过xmlreadercreate静态方法打开xml文件,并通过read一个节点的进行读取,并判断该节点的类型。

    /// <summary>
    /// readxmlstream类
    /// </summary>
    public static class readxmlstream
    {
        public static string path
        {
            get
            {
                string path = @"..\..\stream.xml";
                return path;
            }
        }

        /// <summary>
        /// 流式处理xml
        /// </summary>
        public static void readxml()
        {
            xmlreader reader = xmlreader.create(path);
            while (reader.read())
            {
                if (reader.nodetype == xmlnodetype.element && reader.name.equals("item"))
                {
                    xelement xe = xnode.readfrom(reader) as xelement;
                    console.writeline(xe.value.trim());
                }
            }
            console.read();
        }
    }

    class program
    {
        static void main(string[] args)
        {
            #region linq 处理xml流
            readxmlstream.readxml();
            #endregion
        }
    }

    运行结果如下:

C# LINQ学习笔记五:LINQ to XML