C# LINQ Learning Notes 5: LINQ to XML

Extract this note from: https://www.cnblogs.com/yaozhenfa/p/CSharp_Linq_For_Xml.html And record the learning process for future reference.

1. Generating xml

1.1 Create simple xml

    /// <summary>
    /// CreateXml class
    /// </summary>
    public class CreateXml
    {
        /// <summary>
        /// Return xml File Path
        /// </summary>
        public string Path
        {
            get
            {
                string path = @"..\..\LinqToXml.xml";
                return path;
            }
        }

        /// <summary>
        /// Create simple xml And save
        /// </summary>
        public void CreateElement()
        {
            XDocument xdoc = new XDocument
                (
                    //Create a xml File
                    //Set this xml Version 1 of.0,Use utf - 8 Code, followed by yes Represents the xml Is independent.
                    new XDeclaration("1.0", "utf-8", "yes"),
                    //Start by creating each node, starting with Root Node, and then Root Add two to the node Item Node.
                    new XElement
                    (
                        "Root",
                        new XElement("Item", "1"),
                        new XElement("Item", "2")
                    )
                );
            xdoc.Save(Path);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            #region Create simple xml
            CreateXml xml = new CreateXml();
            xml.CreateElement();
            #endregion
        }
    }

The resulting xml is as follows:

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

* 1.2 Create xml comments

When there are many items in xml, we need to use comments to distinguish them, and through linq to xml we can also add comments to them.

    /// <summary>
    /// CreateXml class
    /// </summary>
    public class CreateXml
    {
        /// <summary>
        /// Return xml File Path
        /// </summary>
        public string Path
        {
            get
            {
                string path = @"..\..\LinqToXml.xml";
                return path;
            }
        }

        /// <summary>
        /// Establish xml Notes
        /// </summary>
        public void CreateComment()
        {
            XDocument xdoc = new XDocument
                (
                    new XDeclaration("1.0", "utf-8", "yes"),
                    new XComment("Here are the notes"),
                    new XElement
                        (
                            "Root",
                            new XElement("Item", "1"),
                            new XElement("Item", "2")
                        )
                );
            xdoc.Save(Path);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            #region LINQ Establish xml Notes
            CreateXml xml = new CreateXml();
            xml.CreateComment();
            #endregion
        }
    }

The resulting xml is as follows:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!--Here are the notes-->
<Root>
  <Item>1</Item>
  <Item>2</Item>
</Root>

1.3 Create xml from object

Many times, we convert types such as arrays into xml to be stored in permanent storage.

    /// <summary>
    /// CreateXml class
    /// </summary>
    public class CreateXml
    {
        /// <summary>
        /// Return xml File Path
        /// </summary>
        public string Path
        {
            get
            {
                string path = @"..\..\LinqToXml.xml";
                return path;
            }
        }

        /// <summary>
        /// Create from Object xml And save
        /// </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 Create from Object xml
            CreateXml xml = new CreateXml();
            xml.CreateElementByObjects();
            #endregion
        }
    }

The resulting xml is as follows:

<?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 Create xml attributes

Sometimes we don't want to create new subitems to save data, but use attributes to do so.As a matter of course, linq to xml also supports this feature, so here's a simple statement

Implement it.

    /// <summary>
    /// CreateXml class
    /// </summary>
    public class CreateXml
    {
        /// <summary>
        /// Return xml File Path
        /// </summary>
        public string Path
        {
            get
            {
                string path = @"..\..\LinqToXml.xml";
                return path;
            }
        }

        /// <summary>
        /// Establish xml attribute
        /// </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 Establish xml attribute
            CreateXml xml = new CreateXml();
            xml.CreateAttribute();
            #endregion
        }
    }

The resulting xml is as follows:

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <Item V1="1" V2="2" />
</Root>

1.5 Create xml namespace

For some enterprise XML formats, this can be very strict, especially if duplicates may occur in the same xml, but we want to distinguish one from the other, at which point we can use the namespace to

They are separated (similar to namespaces in C#).

    /// <summary>
    /// CreateXml class
    /// </summary>
    public class CreateXml
    {
        /// <summary>
        /// Return xml File Path
        /// </summary>
        public string Path
        {
            get
            {
                string path = @"..\..\LinqToXml.xml";
                return path;
            }
        }

        /// <summary>
        /// Establish xml Namespace
        /// </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 Establish xml Namespace
            CreateXml xml = new CreateXml();
            xml.CreateNamespace();
            #endregion
        }
    }

The resulting xml is as follows:

<?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>

From this result, we can see that there is an xmlns attribute in the corresponding attribute, and the value is the namespace we give it.

2. Query and modify Xml

linq to xml is not only easy to create but also very convenient for querying, editing, and deleting.

Create an XmlReadWrite.xml file:

<?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 Read xml files

    /// <summary>
    /// QueryXml class
    /// </summary>
    public class QueryXml
    {
        /// <summary>
        /// Return xml File Path
        /// </summary>
        public string Path
        {
            get
            {
                string path = @"..\..\XmlReadWrite.xml";
                return path;
            }
        }

        /// <summary>
        /// read xml file
        /// </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 read xml file
            QueryXml xml = new QueryXml();
            xml.QueryElementByFile();
            #endregion
        }
    }

The results are as follows:

In the example above, we use XElement's static method Load to read an xml file under a specified path, and also get the value of the first item of the xml file and output it.

2.2 Add new nodes before and after xml specified nodes

    /// <summary>
    /// QueryXml class
    /// </summary>
    public class QueryXml
    {
        /// <summary>
        /// Return xml File Path
        /// </summary>
        public string Path
        {
            get
            {
                string path = @"..\..\XmlReadWrite.xml";
                return path;
            }
        }

        /// <summary>
        /// stay xml Add new nodes before and after specified nodes
        /// </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 stay xml Add new nodes before and after specified nodes
            QueryXml xml = new QueryXml();
            xml.AddElementBeforeAndAfter();
            #endregion
        }
    }

The resulting xml is as follows:

<?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 Add attributes to xml nodes

You can add nodes dynamically, but when you create a node, you can not only create a node, but also create attributes. Here we can add new attributes through SetAttributeValue or

Modify existing properties.

    /// <summary>
    /// QueryXml class
    /// </summary>
    public class QueryXml
    {
        /// <summary>
        /// Return xml File Path
        /// </summary>
        public string Path
        {
            get
            {
                string path = @"..\..\XmlReadWrite.xml";
                return path;
            }
        }

        /// <summary>
        /// Add attributes to xml In node
        /// </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 Add attributes to xml In node
            QueryXml xml = new QueryXml();
            xml.AddAttributeToElement();
            #endregion
        }
    }

The resulting xml is as follows:

<?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 Before and after adding comments to xml specified nodes

The syntax here is basically similar to [Add new nodes before and after the specified node in the xml], except that the XML is read in a different way.

    /// <summary>
    /// QueryXml class
    /// </summary>
    public class QueryXml
    {
        /// <summary>
        /// Return xml File Path
        /// </summary>
        public string Path
        {
            get
            {
                string path = @"..\..\XmlReadWrite.xml";
                return path;
            }
        }

        /// <summary>
        /// Add comments to xml Before and after the specified node
        /// </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("Previous comments");
                XComment acom = new XComment("Comments after");
                item.AddBeforeSelf(bcom);
                item.AddAfterSelf(acom);
            }
            tr.Close();
            xe.Save(Path);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            #region LINQ Add comments to xml Before and after the specified node
            QueryXml xml = new QueryXml();
            xml.AddCommentBeforeAndAfter();
            #endregion
        }
    }

The resulting xml is as follows:

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <!--Previous comments-->
  <Item v1="1" v2="2">Item1</Item>
  <!--Comments after-->
  <Item v1="1" v2="2" v3="3">Item2</Item>
</Root>

2.5 Replace xml specified node

SetValue modifies the value of a node, but sometimes child nodes are involved and we want to replace them all at once, so we need to use ReplaceWith.

    /// <summary>
    /// QueryXml class
    /// </summary>
    public class QueryXml
    {
        /// <summary>
        /// Return xml File Path
        /// </summary>
        public string Path
        {
            get
            {
                string path = @"..\..\XmlReadWrite.xml";
                return path;
            }
        }

        /// <summary>
        /// replace xml Specify Node
        /// </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 replace xml Specify Node
            QueryXml xml = new QueryXml();
            xml.ReplaceElement();
            #endregion
        }
    }

The resulting xml is as follows:

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <!--Previous comments-->
  <Item v1="1" v2="2">Item1</Item>
  <!--Comments after-->
  <Item>Item3</Item>
</Root>

2.6 Delete xml specified properties

Earlier we described creating, modifying, and adding attributes, but we haven't yet described how to delete the specified attributes. Here's a simple example.

    /// <summary>
    /// QueryXml class
    /// </summary>
    public class QueryXml
    {
        /// <summary>
        /// Return xml File Path
        /// </summary>
        public string Path
        {
            get
            {
                string path = @"..\..\XmlReadWrite.xml";
                return path;
            }
        }

        /// <summary>
        /// delete xml Specify Attributes
        /// </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 delete xml Specify Attributes
            QueryXml xml = new QueryXml();
            xml.RemoveAttribute();
            #endregion
        }
    }

The resulting xml is as follows:

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <!--Previous comments-->
  <Item v1="1">Item1</Item>
  <!--Comments after-->
  <Item>Item3</Item>
</Root>

2.7 Delete xml specified node

Now that it is possible to delete attributes above, it is natural to delete attributes as well.

    /// <summary>
    /// QueryXml class
    /// </summary>
    public class QueryXml
    {
        /// <summary>
        /// Return xml File Path
        /// </summary>
        public string Path
        {
            get
            {
                string path = @"..\..\XmlReadWrite.xml";
                return path;
            }
        }

        /// <summary>
        /// delete xml Specify Node
        /// </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 delete xml Specify Node
            QueryXml xml = new QueryXml();
            xml.RemoveElement();
            #endregion
        }
    }

The resulting xml is as follows:

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <!--Previous comments-->
  <Item v1="1">Item1</Item>
  <!--Comments after-->
</Root>

3. Query by Node Relations

The above queries are queried by related criteria, but sometimes we just need to go through the relationship, which avoids a lot of code, and of course a little bit of exploration will reveal it

Real XElement s are provided to us.

Create a Structure.xml file:

<?xml version="1.0" encoding="utf-8" ?>
<Root>
  <Item>
    <SubItem1>
      1
    </SubItem1>
    <SubItem>
      <Child>
        sss
      </Child>
    </SubItem>
    <SubItem2>
      2
    </SubItem2>
  </Item>
</Root>

3.1 Displays all parent nodes of the xml specified node

From the xml file above, we clearly see that xml is structured and related to each other, but now we need to show the name of the parent node of a node.

    /// <summary>
    /// StructureXml class
    /// </summary>
    public class StructureXml
    {
        public string Path
        {
            get
            {
                string path = string.Format(@"..\..\Structure.xml");
                return path;
            }
        }

        /// <summary>
        /// display xml All parent nodes of the specified node
        /// </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}The up parent node of is:");
                foreach (var upper in item.Ancestors())
                {
                    Console.WriteLine(upper.Name);
                }
                Console.WriteLine("----------------------------");
                Console.WriteLine($"{item.Name}And up parent nodes are:");
                foreach (var selfAndUpper in item.AncestorsAndSelf())
                {
                    Console.WriteLine(selfAndUpper.Name);
                }
                Console.Read();
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            #region LINQ display xml All parent nodes of the specified node
            StructureXml xml = new StructureXml();
            xml.ShowAllParentElement();
            #endregion
        }
    }

The results are as follows:

3.2 Displays all the child nodes of the xml specified node

Not only can we output all the parent nodes of a node, but also all the child nodes of a node.

    /// <summary>
    /// StructureXml class
    /// </summary>
    public class StructureXml
    {
        public string Path
        {
            get
            {
                string path = string.Format(@"..\..\Structure.xml");
                return path;
            }
        }

        /// <summary>
        /// display xml All child nodes of the specified node
        /// </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 display xml All child nodes of the specified node
            StructureXml xml = new StructureXml();
            xml.ShowAllChildElement();
            #endregion
        }
    }

The results are as follows:

3.3 Displays nodes before xml siblings

Now that there is a parent-child relationship, of course, peer relationship is also necessary. First, let's show the nodes before peer nodes.

    /// <summary>
    /// StructureXml class
    /// </summary>
    public class StructureXml
    {
        public string Path
        {
            get
            {
                string path = string.Format(@"..\..\Structure.xml");
                return path;
            }
        }

        /// <summary>
        /// display xml Node before sibling node
        /// </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($"and{item.Name}The first nodes of the same level are:");
                foreach (var sub in item.ElementsBeforeSelf())
                {
                    Console.WriteLine(sub.Name);
                }
            }
            Console.Read();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            #region LINQ display xml Node before sibling node
            StructureXml xml = new StructureXml();
            xml.ShowPrevElement();
            #endregion
        }
    }

The results are as follows:

3.4 Displays nodes after xml siblings

    /// <summary>
    /// StructureXml class
    /// </summary>
    public class StructureXml
    {
        public string Path
        {
            get
            {
                string path = string.Format(@"..\..\Structure.xml");
                return path;
            }
        }

        /// <summary>
        /// display xml Node after sibling node
        /// </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($"and{item.Name}Posterior nodes of the same level are:");
                foreach (var sub in item.ElementsAfterSelf())
                {
                    Console.WriteLine(sub.Name);
                }
            }
            Console.Read();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            #region LINQ display xml Node after sibling node
            StructureXml xml = new StructureXml();
            xml.ShowNextElement();
            #endregion
        }
    }

The results are as follows:

4. Listen for xml events

You might wonder why xml listens?It makes sense, for example, if you depend on a node's value, then you listen on that node if it changes

Then you can react in time.However, xml's event monitoring has a feature, similar to DOM events in browsers, that parent nodes can also listen to events of their children.

Here's a simple example to illustrate:

    /// <summary>
    /// EventXml class
    /// </summary>
    public static class EventXml
    {
        public static void BindChangeing()
        {
            XElement xe = new XElement("Root");
            xe.Changing += XElement_Changing;
            xe.Changed += XElement_Changed;
            //Add Elements
            xe.Add(new XElement("Item", "1"));
            var item = xe.Element("Item");
            //Replace Element
            item.ReplaceWith(new XElement("Item", "2"));
            //Delete element
            item = xe.Element("Item");
            item.Remove();
            //Read results
            Console.Read();
        }

        static void XElement_Changing(object sender, XObjectChangeEventArgs e)
        {
            XElement xe = sender as XElement;
            Console.WriteLine($"{xe.Name}Underway{e.ObjectChange}In operation, sender={sender.ToString()}. ");
        }

        static void XElement_Changed(object sender, XObjectChangeEventArgs e)
        {
            XElement xe = sender as XElement;
            Console.WriteLine($"{xe.Name}Completed{e.ObjectChange}Operations, sender={sender.ToString()}. \n");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            #region LINQ Monitor xml Event
            EventXml.BindChangeing();
            #endregion
        }
    }

The results are as follows:

5. Processing xml streams

In practical commercial development, it is impossible for xml to only store such a small amount of data, possibly a very large amount of data.If we were to continue the way we used to, we would read all the xml in

Memory, which can consume a lot of memory and affect the performance of the system.In this case, we need to use streaming to process the xml, because the stream reads part of the XML into memory in our order.

Not all xml will be read into memory.

Create a Stream.xml file:

<?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>

Here we open the xml file by using XmlReader's Create static method, read it from a Read node, and determine the type of the node.

    /// <summary>
    /// ReadXmlStream class
    /// </summary>
    public static class ReadXmlStream
    {
        public static string Path
        {
            get
            {
                string path = @"..\..\Stream.xml";
                return path;
            }
        }

        /// <summary>
        /// Streaming 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 Handle xml flow
            ReadXmlStream.ReadXml();
            #endregion
        }
    }

The results are as follows:

Keywords: C# xml encoding Attribute React

Added by andrewgk on Sat, 28 Dec 2019 12:06:02 +0200