#
第十九章 使用%XML.TextReader
`%XML.TextReader`类提供了一种简单、容易的方法来读取可能直接映射到InterSystems IRIS对象,也可能不直接映射到InterSystems IRIS对象的任意XML文档。具体地说,该类提供了导航格式良好的XML文档并查看其中信息(元素、属性、注释、名称空间URI等)的方法。该类还基于`DTD`或`XML`架构提供完整的文档验证。但是,与`%XML.Reader`不同的是,`%XML.TextReader`不提供返回`DOM`的方法。如果需要DOM,请参阅前面的“将XML导入对象”一章。
**注意:使用的任何XML文档的XML声明都应该指明该文档的字符编码,并且文档应该按照声明的方式进行编码。如果未声明字符编码,InterSystems IRIS将使用前面的“输入和输出的字符编码”中描述的默认值。如果这些默认值不正确,请修改XML声明,使其指定实际使用的字符集。**
# 创建文本阅读器`Text Reader`方法
要读取不一定与 IRIS对象类有任何关系的任意XML文档,可以调用`%XML.TextReader`类的方法,该类将打开文档并将其作为文本阅读器对象加载到临时存储中。文本阅读器对象包含一个可导航的节点树,每个节点都包含有关源文档的信息。然后,方法可以导航该文档并查找有关该文档的信息。对象的属性提供有关文档的信息,这些信息取决于在文档中的当前位置。如果存在验证错误,这些错误也可以作为树中的节点使用。
## 整体结构
法应执行以下部分或全部操作:
1. 通过以下方法之一的第一个参数指定文档源:
`Method`| `First Argument`
---|---
`ParseFile()` |文件名,带有完整路径。请注意,文件名和路径只能包含ASCII字符。
`ParseStream()`|流
`ParseString()`| 字符串
`ParseURL()`| URL
**在任何情况下,源文档都必须是格式良好的XML文档;也就是说,它必须遵守XML语法的基本规则。这些方法中的每一个都返回一个状态(`$OK`或失败代码),以指示结果是否成功。可以使用常用机制测试状态;特别是可以使用`$System.Status.DisplayError(status)`查看错误消息的文本。**
对于这些方法中的每一个,如果该方法返回$OK,则它通过引用(其第二个参数)返回包含XML文档中的信息的文本阅读器对象。
其他参数允许控制实体解析、验证、找到哪些项等。这些内容将在本章后面的“解析方法的参数列表”中介绍。
2. 检查解析方法返回的状态,并在适当的情况下退出。
如果解析方法返回$OK,则有一个与源XML文档相对应的文本阅读器对象。可以导航此对象。
文档可能包含`“element”`、`“endelement”`、`“startprefixmapping”`等节点。
重要提示:在任何验证错误的情况下,文档包含“错误”或“警告”节点。
代码应该检查这些节点。
3. 使用以下实例方法之一开始读取文档。
- 使用`Read()`导航到文档的第一个节点。
- 使用`ReadStartElement()`导航到特定类型的第一个元素。
- 使用`MoveToContent()`导航到类型为`“chars”`的第一个节点。
4. 获取该节点感兴趣的属性的值(如果有的话)。可用的属性包括名称、值、深度等。
5. 根据需要继续在文档中导航并获取属性值。
如果当前节点是元素,则可以使用`MoveToAttributeIndex()`或`MoveToAttributeName()`方法将焦点移至该元素的属性。若要返回到元素(如果适用),请使用`MoveToElement()`。
6. 如果需要,可以使用`Rewind()`方法返回到文档的开头(第一个节点之前)。这是唯一可以在源代码中倒退的方法。
方法运行后,文本读取器对象将被销毁,所有相关的临时存储都将被清除。
## 示例1
下面是一个简单的方法,它可以读取任何XML文件,并显示每个节点的序列号、类型、名称和值:
```java
/// w ##class(PHA.TEST.Xml).WriteNodes("E:\temp\textReader.txt")
ClassMethod WriteNodes(myfile As %String)
{
set status = ##class(%XML.TextReader).ParseFile(myfile,.textreader)
//检查状态
if $$$ISERR(status) {do $System.Status.DisplayError(status) quit}
//逐个节点遍历文档
while textreader.Read()
{
Write !, "Node ", textreader.seq, " is a(n) "
Write textreader.NodeType," "
If textreader.Name'="" {
Write "named: ", textreader.Name
} Else {
Write "and has no name"
}
Write !, " path: ",textreader.Path
If textreader.Value'="" {
Write !, " value: ", textreader.Value
}
}
q ""
}
```
此示例执行以下操作:
1. 它调用`ParseFile()`类方法。这将读取源文件,创建一个文本阅读器对象,并通过引用在变量doc中返回该对象。
2. 如果`ParseFile()`成功,则该方法然后调用`read()`方法来查找文档中的每个后续节点。
3. 对于每个节点,该方法写入包含节点序列号、节点类型、节点名称(如果有)、节点路径和节点值(如果有)的输出行。输出将写入当前设备。
以下示例源文档:
```xml
yaoxin
1990-04-25
```
对于此源文档,前面的方法生成以下输出:
```java
DHC-APP>w ##class(PHA.TEST.Xml).WriteNodes("E:\temp\textReader.txt")
Node 1 is a(n) processinginstruction named: xml-stylesheet
path:
value: type="text/css" href="mystyles.css"
Node 2 is a(n) element named: Root
path: /Root
Node 3 is a(n) startprefixmapping named: s01
path: /Root
value: s01 http://www.root.org
Node 4 is a(n) element named: s01:Person
path: /Root/s01:Person
Node 5 is a(n) element named: Name
path: /Root/s01:Person/Name
Node 6 is a(n) chars and has no name
path: /Root/s01:Person/Name
value: yaoxin
Node 7 is a(n) endelement named: Name
path: /Root/s01:Person/Name
Node 8 is a(n) element named: DOB
path: /Root/s01:Person/DOB
Node 9 is a(n) chars and has no name
path: /Root/s01:Person/DOB
value: 1990-04-25
Node 10 is a(n) endelement named: DOB
path: /Root/s01:Person/DOB
Node 11 is a(n) endelement named: s01:Person
path: /Root/s01:Person
Node 12 is a(n) endprefixmapping named: s01
path: /Root
value: s01
Node 13 is a(n) endelement named: Root
path: /Root
```
请注意,注释已被忽略;默认情况下,`%XML.TextReader`忽略注释。
## Example 2
下面的示例读取一个XML文件并列出其中的每个元素
```java
/// w ##class(PHA.TEST.Xml).ShowElements("E:\temp\textReader.txt")
ClassMethod ShowElements(myfile As %String)
{
set status = ##class(%XML.TextReader).ParseFile(myfile,.textreader)
if $$$ISERR(status) {do $System.Status.DisplayError(status) quit}
while textreader.Read()
{
if (textreader.NodeType = "element")
{
write textreader.Name,!
}
}
q ""
}
```
此方法使用`NodeType`属性检查每个节点的类型。如果节点是元素,则该方法将其名称打印到当前设备。对于前面显示的XML源文档,此方法生成以下输出:
```java
DHC-APP>w ##class(PHA.TEST.Xml).ShowElements("E:\temp\textReader.txt")
Root
s01:Person
Name
DOB
```
# 节点类型
文档的每个节点都是以下类型之一:
文本阅读器文档中的节点类型
Type| Description
---|---
`"attribute"` |XML属性。
`"chars"` |一组字符(如元素的内容)。`%XML.TextReader`类识别其他节点类型(`“CDATA”`、`“EntityReference”`和`“EndEntity”`),但自动将它们转换为“字符”。
`"comment"`| XML注释。
`"element"`|XML元素的开始。
`"endelement"`|XML元素的结束。
`"endprefixmapping"`| 声明名称空间的上下文的结束。
`"entity"`|XML实体。
`"error"`| 解析器发现的验证错误。
`"ignorablewhitespace"`| 混合内容模型中标记之间的空白。
`"processinginstruction"`|XML处理指令。
`"startprefixmapping"`|XML命名空间声明,它可能包括也可能不包括命名空间。
`"warning"`| 解析器发现验证警告。
请注意,XML元素由多个节点组成。例如,以下XML片段:
```xml
Willeke,Clint B.
1925-10-01
```
SAX解析器将此XML视为以下节点集:
文档节点示例
Node Number |Type of Node| Name of Node, If Any| Value of Node, If Any
---|---|---|---
1 |element |Person
2| element |Name
3| chars || Willeke,Clint B.
4 |endelement| Name
5| element| DOB
6| chars || 1925-10-01
7| endelement| DOB
8| endelement| Person
例如,注意``元素被认为是三个节点:一个元素节点、一个字符节点和一个结束元素节点。还要注意,该元素的内容只能作为`chars`节点的值使用。