Unity/C# 常用XML读写方式详解(LINQ to XML、XmlReader/Writer)
此文章将会介绍C#中进行XML读写的方式:LINQ to XML随机读写、XmlReader/Writer流式读写
用于初学者参考或作为工具书查阅。
- LINQ to XML
- 基本概念和类
- XElement常用方法
- 创建XML
- 查询:LINQ 查询语法(Query Syntax)
- 排序、中间值
- 编辑XML
- XMLReader/XMLWriter
- XML结构
- 常见的节点类型与示例:
- 使用场景和注意事项:
- MoveTo...()方法
- 详细说明:
- ReadTo...()方法
- 详细说明:
- 总结对比:
- 结束
LINQ to XML
首先介绍LINQ to XML,这是更现代、更直观的XML操作方式。它使得你可以使用 LINQ 查询语法对 XML 文档进行操作,同时也能执行插入、删除、修改等操作。
与XMLDocument
相比,LINQ to XML
效率更高、内存占用更低。
基本概念和类
如果你对XML结构略有疑问,在
流式处理XML
章节有详细的XML结构介绍以及解析。
XDocument、XElement、XAttribute是最常用的元素,我使用🌟标记。
类 | 描述 |
---|---|
XDocument 🌟 | 表示整个 XML 文档的类。它可以存储根元素及其所有子元素 |
XElement 🌟 | 表示 XML 中的一个元素节点。它代表了 XML 元素,包括名称 、属性 和子元素 |
XAttribute 🌟 | 代表 XML 中的一个属性。每个 XElement 对象可以包含多个 XAttribute 对象 |
XNamespace | 表示 XML 中的命名空间。用于在查询和操作带有命名空间的 XML 文档时,指定正确的命名空间 |
XText | 表示 XML 中的文本节点。每个 XElement 可以有一个文本节点,包含该元素的文本值 |
XComment | 代表 XML 中的注释节点 |
XProcessingInstruction | 代表 XML 中的处理指令节点(例如 <?xml version="1.0"?> ) |
XDocumentType | 表示 XML 文档类型声明节点(<!DOCTYPE> )。通常用于定义文档的类型、结构和规则 |
要获取某个元素节点的内容,可读取其Value
属性,或者将其本身强制转换为预期的基础类型。
要设置某个元素节点的内容,可设置其Value
属性,或者使用SetValue(Object o)
方法
ℹ️注意:
这些元素都实现了向基础类型的强制转换运算符,即转换是安全且有意义的,例如:XElement root = XElement.Parse("<Root>abc <b>def </b>ghi</Root>"); //将 XElement 强制转换为 string,其值将自动为:root.value Console.WriteLine("root={0}", (string)root);
这将输出root的内容:
abc def ghi
XElement常用方法
XElement
是 XDocument
的基础构建块,是整个 XML 操作体系的核心,它包含常用的方法:
XElement 方法 | 描述 |
---|---|
Add | 向元素添加子元素、文本、注释等。 重载:可以添加多个元素、文本、注释或其他节点。常用的重载包括: 1. Add(params object[] content) :接受多个对象,支持添加 XElement 、XText 、XComment 等。2. Add(XElement element) :添加单个元素。 |
Remove | 移除当前元素的子元素、属性或其他节点。 重载:可以移除单个节点或一组节点。 |
Descendants | 返回当前元素及其所有后代元素的集合。 重载:可以指定过滤条件来获取符合条件的后代元素。例如: 1. Descendants(XName name) :返回符合特定名称的后代元素。2. Descendants(XName name, XNamespace ns) :返回符合特定名称和命名空间的后代元素。 |
Elements | 返回当前元素的所有直接子元素。 重载:可以指定过滤条件来获取符合条件的子元素。例如: 1. Elements(XName name) :返回符合特定名称的子元素。2. Elements(XName name, XNamespace ns) :返回符合特定名称和命名空间的子元素。 |
Attribute | 获取或设置与当前元素关联的特定属性。 重载:可以通过属性的名称来访问或设置属性值。 1. Attribute(XName name) :获取特定名称的属性。2. Attribute(XName name, XNamespace ns) :获取带命名空间的特定名称的属性。 |
HasElements | 判断当前元素是否包含子元素。返回 true 如果元素包含子元素,否则返回 false 。 |
Value | 获取或设置元素的文本值。如果元素有子元素,返回其所有子元素的文本拼接;否则返回元素的文本内容。 重载:可以设置元素的文本内容或从子元素中获取文本。 |
Name | 获取或设置元素的名称。包括元素的本地名称和命名空间。 |
FirstNode | 返回当前元素的第一个子节点。 |
LastNode | 返回当前元素的最后一个子节点。 |
Ancestors | 返回当前元素及其所有祖先元素的集合。 重载:可以指定过滤条件来获取符合条件的祖先元素。例如: 1. Ancestors(XName name) :返回符合特定名称的祖先元素。2. Ancestors(XName name, XNamespace ns) :返回符合特定名称和命名空间的祖先元素。 |
Parent | 获取当前元素的父元素。如果当前元素没有父元素,则返回 null 。 |
DescendantsAndSelf | 返回当前元素及其所有后代元素(包括当前元素)。 |
NodeType | 获取当前节点的类型(例如元素、文本、属性等)。 |
GetPrefixOfNamespace | 获取与当前元素关联的命名空间的前缀。 |
RemoveAttributes | 移除当前元素的所有属性。 |
SetAttributeValue | 设置或修改与当前元素关联的属性的值。如果属性不存在,则会创建新属性。 重载:可以为不同类型的属性赋值。例如: 1. SetAttributeValue(XName name, object value) :设置属性的值。 |
SetElementValue | 设置或修改指定子元素的值。如果子元素不存在,则会创建新子元素并设置其值。 重载:可以设置不同类型的值。例如: 1. SetElementValue(XName name, object value) :为指定名称的子元素设置值。 |
这些方法是后续进行增删改查的基础,需对其有清楚的理解。
创建XML
通过链式调用,能够让代码更加紧凑和易读,例如:
var contact =
new XElement("Contact",
new XElement("Name", "Patrick Hines"),
new XElement("Age","22")
new XElement("Phone", "206-555-0144",
new XAttribute("Type", "Home")),
new XElement("Phone", "425-555-0145",
new XAttribute("Type", "Work")),
new XElement("Address",
new XElement("City", "Mercer Island"),
new XElement("State", "WA"),
)
);
生成的XML:
<Contact>
<Name>Patrick Hines</Name>
<Age>22</Age>
<Phone Type="Home">206-555-0144</Phone>
<Phone Type="Work">425-555-0145</phone>
<Address>
<City>Mercer Island</City>
<State>WA</State>
</Address>
</Contact>
查询:LINQ 查询语法(Query Syntax)
官方查询用例文档
LINQ 查询语法类似于 SQL 查询,它是更加直观、声明性的查询方式。如果你有SQL语句基础,那么应该很容易掌握复杂查询的方法。
以上文的XML为例,要查询Type
为Home
的<Phone>
:
XElement root = XElement.Load("Contact.xml");
IEnumerable<XElement> phone =
from el in root.Elements("Phone")
where (string)el.Attribute("Type") == "Home"
select el;
foreach (XElement el in address)
Console.WriteLine(el);
其中用到了Elements(string n)
方法来获取所有n标签。
⚠️再次强调:
el.Attribute("Type")
返回值是XAttribute
,将其强制转换为string
是安全的,因为其实现了向基础类型的类型转换操作符。
排序、中间值
假设XML有多个
<Contact>
元素节点,内容均为随机值。
借助于LINQ 查询语法,很容易对其结果根据年龄进行排序:
IEnumerable<XElement> sortedContacts =
from contact in root.Elements("Contact")
orderby (int)contact.Element("Age")
select contact;
计算中间值的例子,实现根据年龄的奇偶性进行排序:
IEnumerable<XElement> sortedContacts =
from contact in root.Elements("Contact")
let isOdd = (int)contact.Element("Age") % 2
orderby isOdd
select contact;
let用于在查询中创建一个新的临时变量,保存计算结果以便后续使用。
可以在let中进行更复杂的运算,例如实现选择后面紧接 ul 元素的 p 元素:
IEnumerable<XElement> items = from e in doc.Descendants("p") let z = e.ElementsAfterSelf().FirstOrDefault() where z != null && z.Name.LocalName == "ul" select e;
用到了更多的新方法,
Descendants
、ElementsAfterSelf
、FirstOrDefault
,但核心原理依旧是在where中进行数值判断。
其中LocalName
是XName
的一个属性,其获取的是没有命名空间限定符的元素节点的名称。例如: 对于下面的XML文件:<Root xmlns="http://www.4399.com"> <Child>content</Child> </Root>
其Root的
Name
为:{http://www.4399.com}Root
其Root的Name.LocalName
为:Root
其Root的Name.NameSpace
为:http://www.4399.com
编辑XML
使用LINQ to XML编辑XML非常容易,只需要调用XElement
的方法:
增
添加方法 | 说明 |
---|---|
Add | 在子内容的末尾添加内容。 |
AddFirst | 在子内容的开头添加内容。 |
AddAfterSelf | 在同级后面添加内容。 |
AddBeforeSelf | 在同级前面添加内容。 |
这些方法都支持多个重载,以调用XElement.Add(…)为例:
var srcTree = new XElement("Root",
new XElement("Element1", 1),
new XElement("Element2", 2),
);
var xmlTree = new XElement("Root",
new XElement("Child1", 1),
new XElement("Child2", 2),
);
//添加单个元素
xmlTree.Add(new XElement("NewChild", "new content"));
//添加集合
xmlTree.Add(
from el in srcTree.Elements()
where (int)el > 3
select el
);
//什么也不会做
xmlTree.Add(srcTree.Element("这是一个不可能找到的元素"));
删
有些元素有特殊的删除方法:
方法 | 说明 |
---|---|
XAttribute.Remove | 从父节点中移除 XAttribute。 |
XContainer.RemoveNodes | 从 XContainer 中移除子节点。 |
XElement.RemoveAll | 从 XElement 中移除内容和属性。 |
XElement.RemoveAttributes | 移除 XElement 的属性。 |
XElement.SetAttributeValue | 如果传递值 null,则删除该属性。 |
XElement.SetElementValue | 如果传递值 null,则删除子元素。 |
XNode.Remove | 从父节点中移除 XNode。 |
Extensions.Remove | 从父元素中移除源集合中的每个属性或元素。 |
其中SetAttributeValue
、SetElementValue
是其函数的特殊用法。
XNode、XContainer 均包括
XElement
与XDocument
下面是一个官方的案例:
XElement root = XElement.Parse(
@"<Root>
<Child1>
<GrandChild1/>
<GrandChild2/>
<GrandChild3/>
</Child1>
<Child2>
<GrandChild4/>
<GrandChild5/>
<GrandChild6/>
</Child2>
<Child3>
<GrandChild7/>
<GrandChild8/>
<GrandChild9/>
</Child3>
</Root>");
root.Element("Child1").Element("GrandChild1").Remove();
root.Element("Child2").Elements().ToList().Remove();
root.Element("Child3").Elements().Remove();
它将从 Child1 中删除第一个子元素,从 Child2 和 Child3 中删除所有子元素。
注意其中使用了ToList()
,依然能够删除root元素中的数据。
改
下面的方法修改 XElement
:
方法 | 说明 |
---|---|
XElement.Parse | 用已分析的 XML 替换元素。 |
XElement.RemoveAll | 移除元素的所有内容(子节点和属性)。 |
XElement.RemoveAttributes | 移除元素的属性。 |
XElement.ReplaceAll | 替换元素的所有内容(子节点和属性)。 |
XElement.ReplaceAttributes | 替换元素的属性。 |
XElement.SetAttributeValue | 设置属性的值。 如果该属性不存在,则创建该属性。 如果值设置为 null,则移除该属性。 |
XElement.SetElementValue | 设置子元素的值。 如果该元素不存在,则创建该元素。 如果值设置为 null,则移除该元素。 |
XElement.Value | 用指定的文本替换元素的内容(子节点)。 |
XElement.SetValue | 设置元素的值。 |
下面的方法修改 XAttribute
:
方法 | 说明 |
---|---|
XAttribute.Value | 设置属性的值。 |
XAttribute.SetValue | 设置属性的值。 |
下面的方法修改 XNode
、XContainer
(包括 XElement
或 XDocument
):
方法 | 说明 |
---|---|
XNode.ReplaceWith | 用新内容替换节点。 |
XContainer.ReplaceNodes | 用新内容替换子节点: |
XMLReader/XMLWriter
特性 | XmlReader / XmlWriter | LINQ to XML |
---|---|---|
操作方式 | 基于流,逐行读取或写入 | 基于内存的对象模型(DOM),加载整个文档 |
性能 | 高效,适用于大文件,内存占用低 | 性能较低,内存占用较高,适用于中小文件 |
适用场景 | 读取大文件、按需处理、低内存占用 | 简单查询、修改、创建和操作 XML 数据 |
查询能力 | 不支持直接查询,需要手动处理节点 | 支持 LINQ 查询,支持复杂查询、筛选、排序 |
易用性 | 较复杂,手动处理 XML 解析和生成 | 简单易用,支持 LINQ 查询语法 |
修改能力 | 支持写入但不支持修改已读取的节点 | 支持修改 XML 数据,添加、删除、更新节点 |
内存占用 | 低,占用内存少 | 高,需要将整个 XML 文档加载到内存中 |
性能优化 | 适合大规模数据的流式处理,逐步操作 | 适合小规模文档操作,适合内存中的数据 |
在理解XML流式序列化的逻辑之前你需要理解XML结构
XML结构
XmlNodeType 微软官方文档
XmlNodeType
是一个枚举类型,定义了 XmlReader
处理的 XML 文档中可能出现的节点类型。每个节点类型代表 XML 文档结构的一部分,例如元素、属性、文本等。以下是 XmlNodeType
的详细说明:
类型 | 枚举值 | 描述 | 可作为其子节点的元素 | 可作为其父节点的元素 |
---|---|---|---|---|
None | 0 | 当XmlReader的读取方法未被调用时返回此值 | EntityReference, Text | |
Element ✨ | 1 | 元素(例如,<item> ) | Element、Text、Comment、ProcessingInstruction、CDATA、EntityReference | Document、DocumentFragment、EntityReference、Element |
Attribute ✨ | 2 | 属性(例如,id='123' ) | EntityReference, Text | (Attribute 不被视为子节点) |
Text ✨ | 3 | 节点的文本内容 | 无 | Attribute、DocumentFragment、Element、EntityReference |
CDATA | 4 | CDATA部分(例如,<![CDATA[我的转义文本]]> ) | 无 | DocumentFragment、EntityReference 和 Element |
EntityReference | 5 | 对实体的引用(例如,# ) | Element、ProcessingInstruction、Comment、Text、CDATA、EntityReference | Attribute、DocumentFragment、Element、EntityReference |
Entity | 6 | 实体声明(例如,<!ENTITY...> ) | 例如 Text ,表示扩展实体的子节点 (EntityReference) | DocumentType |
ProcessingInstruction | 7 | 处理指令(例如,<?pi test?> ) | 无 | Document、DocumentFragment、Element、EntityReference |
Comment | 8 | 注释(例如,<!-- 我的注释 --> ) | 无 | Document、DocumentFragment、EntityReference |
Document | 9 | 作为文档树的根,提供访问整个XML文档的文档对象 | XmlDeclaration、 Element (最多一个) 、ProcessingInstruction、、 Comment``DocumentType | |
DocumentType | 10 | 文档类型声明由以下标签指示(例如,<!DOCTYPE...> ) | Notation, Entity | |
DocumentFragment | 11 | 文档片段 | Element、ProcessingInstruction、Comment、Text、CDATA、EntityReference | |
Notation | 12 | 文档类型声明中的符号(例如,<!NOTATION...> ) | 无 | DocumentType |
Whitespace | 13 | 标记之间的空白 | ||
SignificantWhitespace | 14 | 混合内容模型中或xml:space="preserve" 范围内标记之间的空白 | ||
EndElement | 15 | 结束元素标签(例如,</item> ) | ||
EndEntity | 16 | 当XmlReader到达实体替换的结尾时返回,这是由于调用了ResolveEntity() | ||
XmlDeclaration | 17 | XML声明(例如,<?xml version='1.0'?> )。XmlDeclaration节点必须是文档中的第一个节点。它不能有子节点。它是文档节点的子节点。它可以有提供版本和编码信息的属性 | 无 | Document |
其中最常用的节点我使用✨将其标识。
常见的节点类型与示例:
假设我们有如下的 XML:
<?xml version="1.0" encoding="UTF-8"?>
<!-- A comment -->
<book title="XML Guide">
<author>John Doe</author>
<![CDATA[This is CDATA content]]>
</book>
解析此 XML 时,XmlReader
会处理以下节点类型:
节点 | 节点类型 (XmlNodeType ) | 描述 |
---|---|---|
<?xml version="1.0" encoding="UTF-8"?> | XmlDeclaration | XML 声明节点。 |
<!-- A comment --> | Comment | 注释节点。 |
<book> | Element | 起始元素节点。 |
title="XML Guide" | Attribute | 属性节点。 |
John Doe | Text | 元素中的文本节点(<author> 的内容)。 |
<![CDATA[This is CDATA content]]> | CDATA | CDATA 节点,表示未解析的字符数据。 |
</book> | EndElement | 结束元素节点。 |
使用场景和注意事项:
-
动态检查节点类型:
你可以通过XmlReader.NodeType
属性动态检查当前节点的类型。例如:if (reader.NodeType == XmlNodeType.Element) { Console.WriteLine($"Start element: {reader.Name}"); } else if (reader.NodeType == XmlNodeType.Text) { Console.WriteLine($"Text content: {reader.Value}"); }
-
跳过非内容节点:
你可以使用MoveToContent()
跳过注释、空白等非内容节点,直接移动到元素或文本节点。 -
特殊节点处理:
某些类型的节点(如Entity
、DocumentFragment
等)通常不会直接被XmlReader
返回。这些节点更多地用于 DOM 模型,而非流式读取。
MoveTo…()方法
XmlReader
中与节点移动相关的成员函数:
函数名 | 介绍 |
---|---|
MoveToAttribute() | 移动到指定的属性节点。如果当前节点是元素节点且存在指定的属性,返回 true ;否则返回 false 。 |
MoveToContent() | 移动到下一个元素节点或文本节点。如果当前节点是元素、文本、注释等类型节点,返回 true ;否则返回 false 。 |
MoveToContentAsync() | 异步版本 MoveToContent() 。该方法返回一个 Task<bool> ,表示操作是否成功。 |
MoveToElement() | 将游标从当前的属性节点移动到包含该属性的元素节点。返回 true 如果移动成功,false 如果当前节点不是属性节点。 |
MoveToFirstAttribute() | 移动到当前元素节点的第一个属性节点。如果当前节点没有属性,返回 false 。 |
MoveToNextAttribute() | 移动到当前元素节点的下一个属性节点。如果没有下一个属性,返回 false 。 |
详细说明:
-
MoveToAttribute()
:- 将游标从当前的元素节点移动到指定名称的属性节点。例如,如果当前在
<book>
元素节点上,可以使用此方法移动到title
或author
等属性。 - 如果指定的属性存在,返回
true
,否则返回false
。
- 将游标从当前的元素节点移动到指定名称的属性节点。例如,如果当前在
-
MoveToContent()
:- 用于跳过当前的非内容节点(例如,空格、注释等),直接跳转到下一个内容节点(例如元素或文本节点)。它会跳过任何不包含实际数据的节点。
- 如果成功跳转到内容节点,返回
true
;如果没有更多的内容节点,返回false
。
-
MoveToContentAsync()
:- 与
MoveToContent()
功能相同,但该方法是异步的。它返回一个Task<bool>
,表示移动是否成功,允许在不阻塞主线程的情况下进行操作。
- 与
-
MoveToElement()
:- 当游标当前位于属性节点时,调用此方法可以将游标移动回包含该属性的元素节点。返回
true
表示成功,否则返回false
。
- 当游标当前位于属性节点时,调用此方法可以将游标移动回包含该属性的元素节点。返回
-
MoveToFirstAttribute()
:- 如果当前元素节点包含属性,调用此方法会将游标移动到第一个属性节点。如果元素没有任何属性,返回
false
。
- 如果当前元素节点包含属性,调用此方法会将游标移动到第一个属性节点。如果元素没有任何属性,返回
-
MoveToNextAttribute()
:- 在当前元素节点的属性列表中,调用此方法会将游标移动到下一个属性节点。如果没有更多的属性,返回
false
。
- 在当前元素节点的属性列表中,调用此方法会将游标移动到下一个属性节点。如果没有更多的属性,返回
这些方法在 XML 文档的解析中非常有用,可以帮助我们在元素和属性之间导航,灵活地获取不同类型的数据。
ReadTo…()方法
XmlReader
中的 ReadToDescendant
、ReadToFollowing
和 ReadToNextSibling
是用于导航和移动游标到 XML 文档中不同节点的方法。它们允许我们跳过当前节点,直接跳到文档中的其他节点。:
函数名 | 介绍 |
---|---|
ReadToDescendant() | 将游标移动到当前节点的第一个子元素节点。如果当前节点没有子元素,返回 false ,否则返回 true 。 |
ReadToFollowing() | 将游标移动到当前节点之后的下一个元素节点。如果找不到符合条件的节点,返回 false 。 |
ReadToNextSibling() | 将游标移动到当前节点的下一个兄弟节点。如果没有兄弟节点,返回 false 。 |
详细说明:
-
ReadToDescendant()
:- 用途:用于将游标直接移动到当前节点的第一个子孙元素节点。如果当前节点有子孙元素,这个方法会跳过所有非元素节点(如文本节点、注释节点等),并停留在第一个子孙元素节点上。
- 返回值:如果成功找到子孙元素节点,返回
true
;如果当前节点没有子孙元素,返回false
。 - 适用场景:这个方法特别适用于你想要快速跳到某个元素的嵌套子元素时。例如,在遍历复杂的 XML 文档时,你可以使用
ReadToDescendant
跳过当前节点,直接进入它的第一个子元素。
示例:
// 假设当前在 <book> 节点上,下面的 XML 结构中有子孙元素 <title> 和 <author>。 if (reader.ReadToDescendant("title")) { // 现在游标已经移动到 <title> 节点。 string title = reader.ReadElementContentAsString(); Console.WriteLine("Title: " + title); }
-
ReadToFollowing()
:- 用途:将游标移动到当前节点之后的下一个符合条件的元素节点。它跳过所有的非元素节点,直到找到下一个元素节点。可以选择指定元素名称,跳到特定类型的节点。
- 返回值:如果成功找到下一个元素节点,返回
true
;如果找不到符合条件的节点,返回false
。 - 适用场景:当你想跳到文档中某个特定位置并继续解析后续元素时,可以使用此方法。你可以指定一个特定的节点名称,跳到下一个匹配的元素。
示例:
// 假设我们当前在 <book> 节点中,下面有 <title> 和 <author> 节点。 // 使用 ReadToFollowing 来跳到下一个符合条件的元素 if (reader.ReadToFollowing("author")) { // 游标已经移动到 <author> 节点 string author = reader.ReadElementContentAsString(); Console.WriteLine("Author: " + author); }
-
ReadToNextSibling()
:- 用途:将游标移动到当前节点的下一个兄弟节点。兄弟节点是指当前节点同一级别上的其他节点。例如,在父节点
<book>
下的兄弟节点可以是<author>
、<title>
等。 - 返回值:如果当前节点有下一个兄弟节点,返回
true
;如果没有兄弟节点,返回false
。 - 适用场景:当你需要遍历同一级别的多个兄弟节点时,可以使用
ReadToNextSibling()
。这在解析具有平行结构的 XML 时特别有用。
示例:
// 假设我们当前在 <title> 节点 // 移动到下一个兄弟节点 <author> if (reader.ReadToNextSibling("author")) { string author = reader.ReadElementContentAsString(); Console.WriteLine("Author: " + author); }
- 用途:将游标移动到当前节点的下一个兄弟节点。兄弟节点是指当前节点同一级别上的其他节点。例如,在父节点
总结对比:
方法 | 功能 | 返回值 | 适用场景 |
---|---|---|---|
ReadToDescendant() | 移动到当前节点的第一个子孙元素节点 | true 或 false | 当你需要进入嵌套的元素节点时,跳过当前节点并寻找子元素。 |
ReadToFollowing() | 移动到当前节点后的下一个元素节点 | true 或 false | 当你需要继续遍历后续元素节点时,跳过非元素节点并找到下一个符合条件的元素。 |
ReadToNextSibling() | 移动到当前节点的下一个兄弟节点 | true 或 false | 当你需要遍历同一层级的元素节点时,跳到下一个兄弟节点。 |
这些方法帮助我们在遍历 XML 文档时,灵活地从当前节点跳转到其他相关节点,避免手动处理节点的复杂层次。
以下是 XmlReader
类成员函数的表格,包括函数名和介绍:
函数名 | 介绍 |
---|---|
Read() | 读取下一个节点并移动游标。如果成功,返回 true ,否则返回 false ,直到文档结束。 |
ReadStartElement() | 读取下一个开始元素节点,并移动游标。如果当前节点不是开始元素,会抛出异常。 |
ReadEndElement() | 读取下一个结束元素节点,并移动游标。如果当前节点不是结束元素,会抛出异常。 |
ReadElementContentAsString() | 读取当前元素节点的内容并作为字符串返回。 |
ReadInnerXml() | 获取当前节点的内部 XML,返回从当前节点开始的所有内容(不包括当前节点本身)。 |
ReadOuterXml() | 获取当前节点的外部 XML,包括当前节点本身及其所有子节点。 |
GetAttribute() | 获取当前节点的指定属性值,如果属性不存在则返回 null 。 |
MoveToAttribute() | 移动到指定的属性节点。返回 true 如果该属性存在,false 如果该属性不存在。 |
MoveToElement() | 将游标移动回元素节点。 |
MoveToFirstAttribute() | 移动到第一个属性节点,如果当前节点没有属性,则返回 false 。 |
MoveToNextAttribute() | 移动到下一个属性节点,返回 true 如果存在下一个属性节点,false 如果没有。 |
IsStartElement() | 检查当前节点是否为开始元素节点,返回 true 如果是,false 如果不是。 |
IsEndElement() | 检查当前节点是否为结束元素节点,返回 true 如果是,false 如果不是。 |
NodeType | 获取当前节点的类型,例如 Element 、Text 、Attribute 等。 |
Name | 获取当前节点的名称(如果是元素节点,则是元素的名称;如果是属性节点,则是属性的名称)。 |
LocalName | 获取当前节点的本地名称,不包含任何命名空间前缀。 |
NamespaceURI | 获取当前节点的命名空间 URI。如果当前节点没有命名空间,则返回空字符串。 |
Depth | 获取当前节点的深度,即当前节点在 XML 树中的层级。 |
IsEmptyElement | 检查当前节点是否是一个空元素(例如 <element /> ),返回 true 或 false 。 |
BaseURI | 获取当前节点的基本 URI。如果无法确定 URI,则返回一个空字符串。 |
HasValue | 检查当前节点是否有值。如果是元素节点且有子节点,或是文本节点,返回 true ;否则返回 false 。 |
Close() | 关闭 XmlReader 实例,释放相关资源。 |
ReadStartElementAsync() | 异步读取下一个开始元素节点。 |
ReadEndElementAsync() | 异步读取下一个结束元素节点。 |
假设我们有一个简单的 XML 片段
<book>
<title lang="en">Introduction to XML</title>
<author>John Doe</author>
</book>
一个伪代码用例为:
// 创建 XmlReader 实例
xmlReader = CreateXmlReader("books.xml")
// 开始读取文档
while (xmlReader.Read()) // 循环直到文件结束
if (xmlReader.IsStartElement()) // 如果当前节点是一个开始元素
if (xmlReader.Name == "title") // 检查节点名称是否为 "title"
title = xmlReader.ReadElementContentAsString() // 获取该元素的内容作为字符串
language = xmlReader.GetAttribute("lang") // 获取 "lang" 属性的值
print("Title: " + title + ", Language: " + language)
else if (xmlReader.Name == "author") // 检查是否为 "author" 元素
author = xmlReader.ReadElementContentAsString() // 获取该元素的内容
print("Author: " + author)
// 关闭 XmlReader 实例
xmlReader.Close()
结束
以上,即为本章的所有内容。
下一篇文章将详细介绍XMLReader/XMLWriter的使用技巧,以及常见但十分隐蔽的误区。