C#(6):Linq To XML:XElement、XDocument
一、概述
Overview - LINQ to XML | Microsoft Docs
LINQ to XMLLINQ to XML 是一种启用了 LINQ 的内存 XML 编程接口,使用它,可以在 .NET Framework.NET Framework 编程语言中处理 XML。
在使用LINQ to XML时需要添加System.Xml.Linq.dll的引用。
- XElement类 表示XML元素,它是XContainer类的派生类,而XContainer类又派生于XNode类。一个元素就是一个节点。
XElement是LINQ to XML最重要最基本的类之一,它包含所有创建和操作XML元素所必需的功能。通过它可以创建元素,添加和修改元素的属性,操作元素的内容等。 - XAttribute类 用来处理属性,属性是与元素相关联的名称/值对。
- XDocument类 提供了处理有效XML文档的方法,包括声明、注释和处理指令。XDocument类派生自XContainer类,可以有子节点。XML标准限值XDocument对象只包含单个XElement子节点,此节点作为根节点或跟元素。
继承关系:
XNode(抽象)类派生类有:XText、XComment、XDocumentType、XProcessingInstruction、XContainer
XContainer(抽象)类派生类有:XElement、XDocument.
二、加载XML文件
1、从文件中输入XML数据
//1、从URI中获取XML数据,支持本地路径和URL,支持对应枚举的设置 XElement xe1 = XElement.Load(@"D:\123.xml",LoadOptions.None); //2、从XmlReader中加载 XmlReader xr = XmlReader.Create(@"D:\123.xml"); XElement xe2 = XElement.Load(xr); //3、从TextReader中获取数据 TextReader reader = File.OpenText(@"D:\123.xml"); XElement xe3 = XElement.Load(reader); //4、从Stream中读取 XElement xe4 = XElement.Load(new FileStream(@"D:\123.xml", FileMode.Open, FileAccess.Read));
2、从字符串中输入XML数据
string xmlString = "刘备28"; XElement xe = XElement.Parse(xmlString, LoadOptions.SetLineInfo);
三、生成XML元素或XML文档
1、创建XML元素
XElement xml = new XElement("Persons", new XElement("Person", new XElement("Name", "刘备"), new XElement("Age", "28") ), new XElement("Person", new XElement("Name", "关羽"), new XElement("Age", "27") ) ); xml.Save(@"D:\123.xml");
2、创建XML文档
//创建处理指令 XProcessingInstruction instruction = new XProcessingInstruction("xml-stylesheet","href=\"hello.css\" type = \"text/css\""); //创建声明对象 XDeclaration xDeclaration = new XDeclaration("1.0","GB2312","yes"); //创建文档类型 XDocumentType documentType = new XDocumentType("Person", null, "Person.dtd", null); //创建XmlCData数据 XCData data = new XCData("
神奇的刘备
"); //创建XDocument文档 XDocument xDoc = new XDocument(); XElement xml = new XElement("Persons", new XElement("Person", new XAttribute("Description", "此人龙凤之姿 天日之表;"), new XElement("Name", data), new XElement("Age", "28") ), new XElement("Person", new XElement("Name", "关羽"), new XElement("Age", "27") ) ); xDoc.Add(documentType); xDoc.Add(instruction); xDoc.Declaration = xDeclaration; xDoc.Add(xml); xDoc.Save(@"D:\123.xml");
3、Linq查询生成XML
我们实例化一个book的集合
Book[] books = new Book[] { new Book("Ajax in Action", "Manning", 2005), new Book("Windows Forms in Action", "Manning", 2006), new Book("RSS and Atom in Action", "Manning", 2006) };
如果我们现在想将Year== 2006的集合创建成以下XML格式
<books> <book title="Windows Forms in Action"> <publisher>Manning</publisher> </book> <book title="RSS and Atom in Action"> <publisher>Manning</publisher> </book> </books>
采用linq方式
XElement xml = new XElement("books", from book in books where book.Year == 2006 select new XElement("book", new XAttribute("title", book.Title), new XElement("publisher", book.Publisher) ) ); // 显示这个XML Console.WriteLine(xml);
传统方式
XmlDocument doc = new XmlDocument(); XmlElement root = doc.CreateElement("books"); foreach (Book book in books) { if (book.Year == 2006) { XmlElement element = doc.CreateElement("book"); element.SetAttribute("title", book.Title); XmlElement publisher = doc.CreateElement("publisher"); publisher.InnerText = book.Publisher; element.AppendChild(publisher); root.AppendChild(element); } } doc.AppendChild(root); // 显示这个XML doc.Save(Console.Out);
4、属性转出元素
XML文件:
<?xml version="1.0" encoding="utf-8" ?> <Root Data1="123" Data2="456"> <Child1>Content</Child1> </Root>
您可以编写一些过程代码以便从属性创建元素,然后删除属性
linq方式:
XElement root = XElement.Load("Data.xml"); XElement newTree = new XElement("Root", root.Element("Child1"), from att in root.Attributes() select new XElement(att.Name, (string)att) ); xml.Save(@"D:\123.xml");
传统方式:
XElement root = XElement.Load("Data.xml"); foreach (XAttribute att in root.Attributes()) { root.Add(new XElement(att.Name, (string)att)); } root.Attributes().Remove();
5、XmlDocument转换为XDocument
XmlDocument doc = new XmlDocument(); doc.LoadXml(xmlStr); //xml字符串转成xml文档对象 XDocument xdoc = doc.ToXDocument(); //xmldocument转成xdoccument 扩展方法 var eventId = xdoc.Document.Root.Element("EventID"); //根节点下的eventid节点 if (eventId != null) { MessageBox.Show(eventId.Value); //15 }
扩展方法
public static class XmlDocumentExtensions { public static XDocument ToXDocument(this XmlDocument document) { return document.ToXDocument(LoadOptions.None); } public static XDocument ToXDocument(this XmlDocument document, LoadOptions options) { using (XmlNodeReader reader = new XmlNodeReader(document)) { return XDocument.Load(reader, options); } } }
四、XML数据的输出
XElement有个Save,这个Save有多种重载,支持将XML数据输入到各处(文件地址,流,TextWriter,XmlWriter)。
XElement xml = new XElement("Persons", new XElement("Person", new XElement("Name", "刘备"), new XElement("Age", "28") ) ); //1、输出到文件 xml.Save(@"D:\123.xml");
//2、输出到TextWriter TextWriter tw = new StringWriter(); //第二个参数SaveOptions枚举支持设置格式,缩进,保留无关重要的空白,去除重复命名空间 xml.Save(tw, SaveOptions.None); Console.WriteLine(tw);
//3、输出到Stream using (MemoryStream mem = new MemoryStream()) { xml.Save(mem); Console.WriteLine(Encoding.UTF8.GetString(mem.ToArray())); }
//4、输出到XmlWriter XmlWriter xw = XmlWriter.Create(@"D:\LinqToXml.xml"); xml.Save(xw);
xw.Flush();
五、查询
- Element() :获取当前XML元素的第一个具有指定名称的子元素
- Elements() :获取当前XML元素的所有子元素,或具有指定名称的所有子元素,返回类型为IEnumerable的可用LINQ进行查询的元素集合
- Attribute(): 获取当前XML元素的具有指定名称的属性
- Attributes(): 获取当前XML元素的所有属性或者具有指定名称的属性, 返回类型为IEnumerable的LINQ集合
1、查询根元素
IEnumerable elements = from e in doc.Elements("Products") select e; foreach (XElement e in elements) { Console.WriteLine("{0}-{1}", e.Name, e.Value); }
2、查询节点
var query = from p in doc.Element("Products").Elements("Product") where (int)p.Element("ProductID") == 1
orderby p.Attribute("ID").Value select p; query.ToList().ForEach(item => { Console.WriteLine("{0}-{1}-{2}", item.Element("ProductID").Value, item.Element("ProductName").Value, item.Element("UnitPrice").Value); });
3、查询子孙节点
Descendants轴方法与Elements类型相似,不过Elements只查找当前元素下的直接子节点,而Descendants则会遍历当前元素下任意层级的子元素。
var query = from b in root.Descendants("Book") select b; foreach (var item in query) { Console.WriteLine(item.Element("ProductName").Value); }
4、查询属性
var query = from p in xml.Nodes().OfType() where (int)p.Attribute("ID").Value == 1 select new { ID = p.Attribute("ID").Value, ProductID = p.Element("ProductID").Value, ProductName = p.Element("ProductName").Value };
5、查询出来填充到List:
XElement root = XElement.Load(@"like.xml"); var query = from ele in root.Elements("book") select new { author = ele.Element("author").Value,
price = ele.Element("price").Value
}; String xml = null; foreach (var item in query) { xml = xml + item.ToString() + "\n ------- \n"; }
六、操作节点
1、增加节点
- Add(): 在 XContainer 的子内容的末尾添加内容。
- AddFirst(): 在 XContainer 的子内容的开头添加内容。
- AddAfterSelf(): 在 XNode 后面添加内容。
- AddBeforeSelf() : 在 XNode 前面添加内容。
XElement product = new XElement ( "Product", new XAttribute("ID", 2), new XElement("ProductName", "LINQ to Object"), new XElement("UnitPrice", 20m), new XElement("Remark", "") ); el.Add(product);
2、修改、替换节点
- SetAttributeValue(): 设置属性的值。 如果该属性不存在,则创建该属性。 如果值设置为 null,则移除该属性。
- SetElementValue(): 设置子元素的值。 如果该元素不存在,则创建该元素。 如果值设置为 null,则移除该元素。
- Value:用指定的文本替换元素的内容(子节点)。
- SetValue(): 设置元素的值。
- ReplaceAll (): 替换元素的所有内容(子节点和属性)。
- ReplaceAttributes(): 替换元素的属性。
- ReplaceWith(): 用新内容替换节点。
- ReplaceNodes(): 用新内容替换子节点。
IEnumerable products = from e in el.Elements("Product") where e.Attribute("ID").Value == "1" select e; if (products.Count() > 0) { XElement product = products.First(); product.SetAttributeValue("ID", 3); product.ReplaceNodes ( new XElement("ProductName", "LINQ to XML Version 2"), new XElement("UnitPrice", 30) ); }
3、删除节点
- RemoveAll(): 移除元素的所有内容(子节点和属性)。
- RemoveAttributes(): 移除元素的属性。
- ReplaceNodes(): 删除子节点。
- Remove(): 移除掉整个节点或节点集合
IEnumerable products = from e in el.Elements("Product") where e.Attribute("ID").Value == "2" select e; if (products.Count() > 0) { products.First().Remove(); } xml.Element("Product").Remove(); // 删除第一个Product子元素 xml.Elements("Product").Remove(); // 删除全部Product子元素 xml.SetElementValue("Product", null); // 删除第一个Product子元素 xml.Element("Product").SetElementValue("ProductID", 1); // 修改ProductID子元素 xml.Element("Product").SetElementValue("ProductID", null); // 删除ProductID子元素
4、属性操作
//添加属性: product.Add(new XAttribute("ID", 1)); //修改属性: product.SetAttributeValue("ID", 2); //删除属性: product.Attribute("ID").Remove();
六、使用XPath查询
为了在LINQ XML中使用XPath查询,需要添加System.Xml.XPath命名空间。如下:
using Sytem.Xml.XPath;
添加了System.Xml.XPath命名空间,XNode类就添加了一系列扩展方法。有了这些扩展方法,我们可以有两种选择处理XML。使我们的应用程序可以进行一个平稳的移植。
- CreateNavigator方法,这允许我们从一个现有的XNode对象创建一个XPathNavigator对象。
- XPathEvaluate方法允许对XNode上的XPath表达式进行计算。
- XPathSelectElement方法返回第一个匹配表达式的元素, XPathSelectElements方法返回所有匹配表达式的元素。
为了查询如下XML数据:
<category name="Technical"> <category name=".NET"> <books> <book>CLR via C#</book> <book>Essential .NET</book> </books> </category> <category name="Design"> <books> <book>Refactoring</book> <book>Domain Driven Design</book> <book>Patterns of Enterprise Application Architecture</book> </books> </category> <books> <book>Extreme Programming Explained</book> <book>Pragmatic Unit Testing with C#</book> <book>Head First Design Patterns</book> </books> </category>
如何使用XPath查询XML数据:
XElement root = XElement.Load("categorizedBooks.xml"); var books = from book in root.XPathSelectElements("//book") select book; foreach (XElement book in books) { Console.WriteLine((string)book); }
七、XML进行转换
1、使用XSLT进行转换
string xsl =@"http://www.w3.org/1999/XSL/Transform'>Book Catalog
by
,
"; XElement books = XElement.Load("books.xml"); XDocument output = new XDocument(); using (XmlWriter writer = output.CreateWriter()) { XslCompiledTransform xslTransformer = new XslCompiledTransform(); xslTransformer.Load(XmlReader.Create(new StringReader(xsl))); xslTransformer.Transform(books.CreateReader(), writer); } Console.WriteLine(output);
为了重用转换代码,可以将转换逻辑封装到一个扩展方法中
public static class XmlExtensions { public static XDocument XslTransform(this XNode node, string xsl) { XDocument output = new XDocument(); using (XmlWriter writer = output.CreateWriter()) { XslCompiledTransform xslTransformer = new XslCompiledTransform(); xslTransformer.Load(XmlReader.Create(new StringReader(xsl))); xslTransformer.Transform(node.CreateReader(), writer); } return output; } } //使用这个扩展方法 XElement.Load("books.xml").XslTransform(xsl));
2、使用 LINQ to XML 转换 XML
XSL 并不是改变 XML 格式的唯一方式(过去它是唯一实际可行的办法),但今天,LINQ to XML 提供了一个富有竞争力的选择。要使用 LINQ to XML 进行转换,你需要一个运用投影的 LINQ 表达式。技巧在于投影必须返回一个 XElement 而不是匿名类型。
string xmlFile = Server.MapPath("DvdList.xml"); XDocument doc = XDocument.Load(xmlFile); XDocument newDoc = new XDocument( new XDeclaration("1.0", "utf-8", "yes"), new XElement("Movies", from DVD in doc.Descendants("DVD") where (int)DVD.Attribute("ID") < 3 select new XElement[] { new XElement ("Moive", new XAttribute("name", (string)DVD.Element("Title")), DVD.Descendants("Star") ) } ) ); string newFile = Server.MapPath("MovieList.xml"); newDoc.Save(newFile);
结果:
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <Movies> <Moive name="The Matrix"> <Star>Keanu Reeves</Star> <Star>Laurence Fishburne</Star> </Moive> <Moive name="Forrest Gump"> <Star>Tom Hanks</Star> <Star>Robin Wright</Star> </Moive> </Movies>
基于 LINQ 转换的语法通常要比使用 XSL 样式表的转换更容易理解,并且更加精确。你也可以很方便的替换为另一个 IEnumable的集合,包括 LINQ to Entities 获得的结果集,然后随意打包成另一种格式的 XML 文档。
posted on 2018-08-19 10:00 springsnow 阅读(1866) 评论(0) 编辑 收藏 举报