1.XML文档的每一个部分(声明、元素、属性、值和文本)都可以用类来表示,如果使用集合属性来存储子内容,可以用一颗对象树完整地表示整个文档,这就叫文档对象模型(document object model)
2.LINQ to DOM,两部分组成:X-DOM,查询符
3.XDocument是XML树的根节点,封装了根XElement。XElement就表示当前节点,XNode就表示子节点,各种各样的子节点都是一种XNode
4.Load方法从文件、URI、Stream、TextReader以及XmlReader创建X-DOM,Parse从字符串创建X-DOM
5.还可以修改X-DOM并保存会xml文档
1.手动创建X-DOM
XElement lastname = new XElement("lastname", "Bloggs");
lastname.Add(new XComment("nice name"));
XElement custom = new XElement("Custom");
custom.Add(new XAttribute("id", 123));
custom.Add(new XElement("firstname", "zhang"));
custom.Add(lastname);
2.函数式创建
XElement custom =
new XElement("Custom", new XAttribute("id", 123),
new XElement("firstname", "zhang"),
new XElement("lastname","bin",
new XComment("nice job")));
3.XElement和XDocument都接受一个params的参数,可以支持函数式创建,Add也可以
4.在X-DOM中可以认为所有对象都为有效的对象
5.自动深度克隆,将同一个节点添加到不同的节点之下,会深度拷贝一份,不会共享。
1.FirstNode、LastNode、Nodes,获得第一个节点,获得最后一个节点,获取所有节点。注意,全部都是直接子节点。获取时,会获取该节点下的所有子节点中的子节点
2.检索元素(XElement),只会获取直接子节点的元素
var a = from cus in custom.Elements()
where cus.Name == "firstname"
select cus.Name;
使用Elements()来代替where,相等才能代替
var b = custom.Elements("firstname");
var c = custom.Elements().Where(s => s.Name == "firstname");
Elements()方法是可以叠加的,但是当使用2个Elements()时,前一个是实例方法,后一个是扩展方法。
3.Element()会返回单个元素,当元素不存在时,使用a.Element("b")?.Value
4.获取整个树的子元素。Descendants可以获取某个Element或者所有的Element。DescendantNodes可以获取所有的Nodes
1.所有的XNode都有一个Parent,虚节点一定是一个Element
2.XDocument没有父节点
3.Parent可以找到父元素,也可以多重Parent,如果超出了,会输出null。
4.Ancestors可以找到所有的祖先,也可以输入字符串,找到特定的祖先,父元素被祖元素包含着。AncestorsAndSelf和Ancestors一样,只是还包括自己。在AncestorsAndSelf调用Last可以直接找到根元素。
使用PreviousNode和NextNode来遍历节点。XNode内部使用链表来存储的,所以PreviousNode效率很低。
1.属性的父节点就是表示该节点的Element
2.FirstAttribute、LastAttribute、Attribute。。。
1.SetValue给Value属性赋值,或者通过Value属性赋值。Value属性只能赋值为字符串,SetValue可以赋一个Object。这个赋值操作会替换所有的子节点,就是不管这个节点下有多少元素,只会替换成这一个
1.Add会将一个节点添加到本节点所有子节点的最后面
2.AddFirst会添加到第一个
3.RemoveNodes删除所有子节点,RemoveAttributes删除所有属性,RemoveAll,一次执行上面2条
4.ReplaceNodes替换子节点
5.ReplaceAttributes替换所有属性
6.ReplaceAll替换所有
7.SetElementValue设置某一子节点的值,SetAttributeValue设置属性的值,没有会自动添加
AddAfterSelf,AddBeforeSelf,Remove,ReplaceWith都是操作当前节点所在的集合的,所以当前节点必须有父节点,如果没有,则会抛出异常。
1.2个Add方法可以添加节点
2.Remove一处当前节点
3.ReplaceWith可以移除当前节点的同时插入其他内容
4.移除批量元素
通过Elements(xxx)来选取节点集合,通过Elements().Where来选取集合,然后Remove,会把当前子节点下符合要求的节点全部删除。
5.删除某个注释节点
//删除某个注释节点
xmlElement.Elements().Where(e=>e.DescendantNodes()
.OfType()
.Any(c=>c.Value == "axb"));
//删除所有注释节点
xmlElement.DescendantNodes().OfType().Remove();
1.设置Value,XML数据有自己的格式,包括字符串、布尔值、日期,当我们为节点赋值时,XML会自动的帮我们用XmlConvert进行转换,保证我们的数据符合XML格式
2.我们输入的数据和XML保存的数据不一定相同,XML不会为我们保存原始数据,所以在类型转换时可能会出错,最好用try/catch
3.在获取属性和节点的值得时候,最好用可空类型接受,这样在节点不存在时也不会报错。还可以用??来去除结果的可空类型
int? a = (int?)xmlElement.Element("fi")?? 3;
4.当节点存在,但是其值为空时,依然会异常。
//fi存在会异常,fi不存在反而不会异常
int? a = (int?)xmlElement.Element("fi");
在LINQ中进行类型转换,添加断言(先用Any判断一下)
5.获取Value值会获取该节点包括所有子节点的文本信息,对Value赋值会将所有子节点用XText节点替换
6.直接添加一个字符串,被当做XText节点
xmlElement.Add("hello");
7.如果只想获取节点下的文本,而不获取子节点下的文本,可以采用在节点下使用FirstNode的方法。因为文本其实也会被当做一个Node来对待。如果该节点下多个文本是分别使用XText创建的,那么他们其实属于不同的XText节点,在获取FirstNode时只会被读取第一个,而如果是用字符串形式创建的,则会被当做同一个Node。
1.XDocument就是根XElement,也有一些Add,Remove方法,但是是有限的。同时添加了一些额外的元素
2.包含一个XElement对象,一个XDeclaration对象,一个DTD独享,任意的XComment,任意XProcessingInstruction
3.XDeclaration即使没有添加,在doc.save时,在文件中也会添加
4.用XDocument在创建X-DOM时,会创建一个根节点,而XElement不会创建根节点
1.XDeclaration有三个对象,版本,编码,standalone,版本永远为"1.0"不管输的是声明,编码使用IETF书写方式
2.ToString输出不会显示声明
3.如果要将XDocument转化成string,同时包含声明,需要用XmlWriter
4.用IO方式来写XML会缺少声明,忽略编码方式
1.如果一个节点定义了一个命名空间,则该节点和它的所有子节点都属于该节点,如果后续的节点不希望继承父节点的命名空间,需要自己指定命名空间,可以指定""
2.指定命名空间的方式
使用xmlns="xxx"的形式,
使用前缀xml,注意使用前缀要同时在其实标签和结束标签都使用
zhang
bin
3.属性也能使用命名空间,但是只能使用前缀的方式
1.创建NameSpace
XNamespace ns = "http://zhang.bin.com";
XName xName = ns + "xname";
2.xml中所有的键值对的key包括节点名的类型都是XName,但是可以用string类型隐式转换
3.namespace可以之间+在XNAME上
1.在创建X-DOM时,默认回忽略命名空间,应该说会指定默认命名空间为"",也就是说如果父节点指定了命名空间(ns+"xname"),而子节点没指定,则子节点的命名空间为"",
2.在导航X-DOM时,如果节点存在命名空间,而导航时不加,则会表示无法找到
3.可以直接用e.Name=ns + e.Name.LocalName来重新指定命名空间
1.可以将原来都是通过xmlns输出的命名空间转为前缀
custom.SetAttributeValue(XNamespace.Xmlns + "ns1", ns1);
2.前缀不会影响构建、查询、更新X-DOM的方式,只要按照完整的(包含命名空间)名称即可
3.只有在序列化到文件或者流的时候才需要使用前缀,确保序列化的时候不会出现不必要的命名空间重复
1.注解可以将任何自定义的数据附加在任何XObject上,可以为根目录设置一个注解,也可以为任意一个子节点设置注解。一个节点可以多个注解
2.最好使用嵌套类来做键,因为查找注解是通过类型来查找的。所以很多时候需要用不同的类型来区分不同的注解
//方法1
XElement cus = new XElement("custom",
from c in persons
select
new XElement("Custom", new XAttribute("id", c.Id),
new XElement("firstname", c.FirstName),
new XElement("lastname", c.LastName)));
//方法2
IEnumerable sql =
from c in persons
select
new XElement("Custom", new XAttribute("id", c.Id),
new XElement("firstname", c.FirstName),
new XElement("lastname", c.LastName));
XElement cus2 = new XElement("Custom", sql);
1.排除空元素
当数据库的数据为空时,要把它设置为NULL,为不是空的Element元素
2.流映射
如果我们的数据映射为X-DOM仅仅为了保存数据(或者调用ToString方法,则可以使用XStreamingElement来替换外层的XElement)。
XStreamingElement只有在Save,ToString或者WriteTo的时候才会加载。但是同时。无法遍历,也无法操作其他很多方法。
Save时会执行多次操作。
3.转换X-DOM
通过查找规律,获取属性或节点的值,构造一个新的X-DOM。
通过查找规律,获取属性或节点的值,对值进行处理,构造一个新的X-DOM。