第十九章 使用%XML.TextReader

第十九章 使用%XML.TextReader

%XML.TextReader类提供了一种简单、容易的方法来读取可能直接映射到InterSystems IRIS对象,也可能不直接映射到InterSystems IRIS对象的任意XML文档。具体地说,该类提供了导航格式良好的XML文档并查看其中信息(元素、属性、注释、名称空间URI等)的方法。该类还基于DTDXML架构提供完整的文档验证。但是,与%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文档中的信息的文本阅读器对象。

其他参数允许控制实体解析、验证、找到哪些项等。这些内容将在本章后面的“解析方法的参数列表”中介绍。

  1. 检查解析方法返回的状态,并在适当的情况下退出。

如果解析方法返回$OK,则有一个与源XML文档相对应的文本阅读器对象。可以导航此对象。

文档可能包含“element”“endelement”“startprefixmapping”等节点。

重要提示:在任何验证错误的情况下,文档包含“错误”或“警告”节点。
代码应该检查这些节点。

  1. 使用以下实例方法之一开始读取文档。
  • 使用Read()导航到文档的第一个节点。
  • 使用ReadStartElement()导航到特定类型的第一个元素。
  • 使用MoveToContent()导航到类型为“chars”的第一个节点。
  1. 获取该节点感兴趣的属性的值(如果有的话)。可用的属性包括名称、值、深度等。
  2. 根据需要继续在文档中导航并获取属性值。

如果当前节点是元素,则可以使用MoveToAttributeIndex()MoveToAttributeName()方法将焦点移至该元素的属性。若要返回到元素(如果适用),请使用MoveToElement()

  1. 如果需要,可以使用Rewind()方法返回到文档的开头(第一个节点之前)。这是唯一可以在源代码中倒退的方法。

方法运行后,文本读取器对象将被销毁,所有相关的临时存储都将被清除。

示例1

下面是一个简单的方法,它可以读取任何XML文件,并显示每个节点的序列号、类型、名称和值:

/// 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 version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="mystyles.css"?>
<Root>
   <s01:Person xmlns:s01="http://www.root.org">
      <Name attr="yx">yaoxin</Name>
      <DOB>1990-04-25</DOB>
   </s01:Person>
</Root>

对于此源文档,前面的方法生成以下输出:

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文件并列出其中的每个元素

/// 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源文档,此方法生成以下输出:

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片段:

<Person>
   <Name>Willeke,Clint B.</Name>
   <DOB>1925-10-01</DOB>
</Person>

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

例如,注意<DOB>元素被认为是三个节点:一个元素节点、一个字符节点和一个结束元素节点。还要注意,该元素的内容只能作为chars节点的值使用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容