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: