第六章 IRIS 将XML文档表示为DOM

使用%XML.Document%XML.Node,可以将任意XML文档表示为DOM(文档对象模型)。然后,您可以导航并修改这个对象。您还可以创建一个新的DOM并添加到其中。

注:

您使用的任何XML文档的XML声明都应该指示该文档的字符编码,并且该文档应该按照声明的方式进行编码。如果未声明字符编码,InterSystems IRIS将使用输入和输出的字符编码中描述的默认值。如果这些默认值不正确,请修改XML声明,使其指定实际使用的字符集。

6.1 以DOM形式打开XML文档

要打开现有的XML文档用作DOM,请执行以下操作:

  1. 创建%XML.Reader的实例。

  2. (可选)指定此实例的“格式”属性,以指定要导入的文件的格式。

    默认情况下,InterSystems IRIS假设XML文件是文字格式的。如果您的文件是SOAP编码的格式,则必须指出这一点,以便能够正确读取文件。

    请参阅将XML导入对象中的Reader属性。

    除非使用Correlate()Next(),否则此属性无效。

  3. 打开源数据。要执行此操作,请使用以下%XML.Reader方法之一:

    • OpenFile() — 打开一个文件。

    • OpenStream() — 打开流。

    • OpenString() — 打开一个字符串。

    • OpenURL() — 打开一个URL。

    在每种情况下,您都可以选择为方法指定第二个参数来覆盖Format属性的值。

  4. 访问Document属性,该属性是一个DOM。此属性是%XML.document的一个实例,它提供了可以用来查找整个文档信息的方法。例如,CountNamespace()返回DOM使用的命名空间总数。

或者,如果您有一个包含XML文档的流,请在调用%XML.DocumentGetDocumentFromStream()方法。这将返回一个%XML.Document的实例。

6.1.1 示例1:将文件转换为DOM

例如,以下方法读取一个XML文件并返回一个表示该文档的%XML.Document实例:

ClassMethod GetXMLDocFromFile(file) As %XML.Document
{
    set reader=##class(%XML.Reader).%New()

    set status=reader.OpenFile(file)
    if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF}

    set document=reader.Document
    quit document
}

6.1.2 示例2:将对象转换为DOM

以下方法接受OREF并返回一个表示该对象的%XML.Document实例。该方法假设OREF是一个启用XML的类的实例:

ClassMethod GetXMLDoc(object) As %XML.Document
{
    //make sure this is an instance of an XML-enabled class
    if '$IsObject(object){
        write "Argument is not an object"
        quit $$$NULLOREF
        }
    set classname=$CLASSNAME(object)
    set isxml=$CLASSMETHOD(classname,"%Extends","%XML.Adaptor")
    if 'isxml {
        write "Argument is not an instance of an XML-enabled class"
        quit $$$NULLOREF
        }
    
    //step 1 - write object as XML to a stream
    set writer=##class(%XML.Writer).%New()
    set stream=##class(%GlobalCharacterStream).%New()
    set status=writer.OutputToStream(stream)
    if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF}
    set status=writer.RootObject(object)
    if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF}

    //step 2 - extract the %XML.Document from the stream
    set status=##class(%XML.Document).GetDocumentFromStream(stream,.document)
    if $$$ISERR(status) {do $System.Status.DisplayError(status) quit $$$NULLOREF}

   quit document
}

6.2 获取DOM的命名空间

当InterSystemsIRIS读取XML文档并创建DOM时,它会识别文档中使用的所有命名空间,并为每个命名空间分配一个索引号。

您的%XML.Document实例类中提供了以下方法,您可以使用这些方法来查找有关文档中命名空间的信息:

CountNamespace()

​ 返回文档中命名空间的数目。

FindNamespace()

​ 返回与给定命名空间相对应的索引。

GetNamespace()

​ 返回给定索引的XML命名空间URI。

以下示例方法显示一个报告,显示文档中使用的命名空间:

ClassMethod ShowNamespaces(doc As %XML.Document)
{
    Set count=doc.CountNamespace()
    Write !, "Number of namespaces in document: "_count
    For i=1:1:count { 
        Write !, "Namespace "_i_" is "_doc.GetNamespace(i)
}

}

另请参见获取有关当前节点的信息。

6.3 导航DOM的节点

要访问文档的节点,可以使用两种不同的技术:

  • 使用%XML.Document实例的GetNode()方法。此方法接受一个整数,该整数表示节点号,从1开始。
  • 调用%XML.Document实例的GetDocumentElement()方法。

此方法返回%XML.Node的实例,该实例提供了用于访问根节点信息和移动到其他节点的属性和方法。以下小节提供了有关使用%XML.Node的详细信息。

  • MoveToFirstChild()
  • MoveToLastChild()
  • MoveToNextSibling()
  • MoveToPreviousSibling()

这些方法中的每一个都试图移动到另一个节点(如方法名称所示)。如果这是可能的,该方法将返回true。如果不是,则返回false,并且焦点与调用该方法之前的焦点相同。

这些方法中的每一个都有一个可选参数skipWhitespace。如果此参数为true,则该方法将忽略任何空白。skipWhitespace的默认值为false。

6.3.1 移动到父节点

要移动到当前节点的父节点,请使用%XML.Node实例的MoveToParent()方法。

此方法采用一个可选参数restrictDocumentNode。如果此参数为true,则方法不会移动到文档节点(根节点)。restrictDocumentNode的默认值为false。

6.3.2 移动到特定节点

要移动到特定节点,可以设置%XML.Node实例的NodeId属性。例如:

   set saveNode = node.NodeId
   //..... lots of processing
   //... 
   // restore position
   set node.NodeId=saveNode

6.3.3 使用id属性

在某些情况下,XML文档可能包括一个名为id的属性,该属性用于标识文档中的不同节点。例如:

<?xml version="1.0"?>
<team>
<member id="alpha">Jack O'Neill</member>
<member id="beta">Samantha Carter</member>
<member id="gamma">Daniel Jackson</member>
</team>

如果(像本例一样)文档使用名为id的属性,则可以使用该属性导航到该节点。为此,您使用文档的GetNodeById()方法,该方法返回一个%XML.Node实例。(请注意,与大多数其他导航方法不同,此方法可从%XML.Document获得,而不是从%XML.Node获得。)

6.4 DOM节点类型

%XML.Document%XML.Node类可识别以下DOM节点类型:

  • Element ($$$xmlELEMENTNODE)

    请注意,这些宏是在%xml.DOM.inc包含文件中定义的。

  • Text ($$$xmlTEXTNODE)

  • Whitespace ($$$xmlWHITESPACENODE)

其他类型的DOM节点被简单地忽略。

请考虑以下XML文档:

<?xml version="1.0"?>
<team>
<member id="alpha">Jack O'Neill</member>
<member id="beta">Samantha Carter</member>
<member id="gamma">Daniel Jackson</member>
</team>

当作为DOM查看时,此文档由以下节点组成:

文档节点示例

NodeIDNodeTypeLocalNameNotes
0,29$$$xmlELEMENTNODEteam
1,29$$$xmlWHITESPACENODE此节点是<team>节点的子节点
1,23$$$xmlELEMENTNODEmember此节点是<team>节点的子节点
2,45$$$xmlTEXTNODEJack O’Neill此节点是第一个<member>节点的子节点
1,37$$$xmlWHITESPACENODE此节点是<team>节点的子节点
1,41$$$xmlELEMENTNODEmember此节点是<team>节点的子节点
3,45$$$xmlTEXTNODESamantha Carter此节点是第二个<member>节点的子节点
1,45$$$xmlWHITESPACENODE此节点是<team>节点的子节点
1,49$$$xmlELEMENTNODEmember此节点是<team>节点的子节点
4,45$$$xmlTEXTNODEDaniel Jackson此节点是第三个<member>节点的子节点
1,53$$$xmlWHITESPACENODE此节点是<team>节点的子节点

有关访问节点类型、localname和其他详细信息的信息,请参阅下一节。

6.5 获取有关当前节点的信息

%XML.Node的以下字符串属性提供了有关当前节点的信息。在所有情况下,如果没有当前节点,就会抛出错误。

LocalName

​ 当前元素节点的本地名称。如果试图访问另一种类型节点的此属性,则会引发错误。

Namespace

​ 当前元素节点的命名空间URI。如果试图访问另一种类型节点的此属性,则会引发错误。

NamespaceIndex

​ 当前元素节点的命名空间的索引。

​ 当InterSystemsIRIS读取XML文档并创建DOM时,它会识别文档中使用的所有名称空间,并为每个名称空间分配一个索引号。

​ 如果试图访问另一种类型节点的此属性,则会引发错误。

Nil

​ 如果此元素节点的xsi:nil或xsi:null为true或1,则等于true。否则,此属性等于false。

NodeData

​ 字符节点的值。

NodeId

​ 当前节点的ID。您可以设置此属性,以便导航到另一个节点。

NodeType

​ 当前节点的类型,如前一节所述。

QName

​ 元素节点的Q名称。仅当前缀对文档有效时,才用于作为XML输出。

以下方法提供了有关当前节点的其他信息:

GetText()

method GetText(ByRef text) as %Boolean

​ 获取元素节点的文本内容。如果返回文本,则此方法返回true;在这种情况下,实际文本被附加到第一个参数,该参数通过引用返回。

HasChildNodes()

method HasChildNodes(skipWhitespace As %Boolean = 0) as %Boolean

​ 如果当前节点具有子节点,则返回true;否则返回false。

GetNumberAttributes()

method GetNumberAttributes() as %Integer

返回当前元素的属性数。

6.5.1 实例

以下示例方法编写一个报告,提供有关当前节点的信息:

ClassMethod ShowNode(node as %XML.Node) 
{
    Write !,"LocalName="_node.LocalName
    If node.NodeType=$$$xmlELEMENTNODE  {
        Write !,"Namespace="_node.Namespace
    }
    If node.NodeType=$$$xmlELEMENTNODE {
        Write !,"NamespaceIndex="_node.NamespaceIndex
     }
    Write !,"Nil="_node.Nil
    Write !,"NodeData="_node.NodeData
    Write !,"NodeId="_node.NodeId
    Write !,"NodeType="_node.NodeType
    Write !,"QName="_node.QName
    Write !,"HasChildNodes returns "_node.HasChildNodes()
    Write !,"GetNumberAttributes returns "_node.GetNumberAttributes()
    Set status=node.GetText(.text)
    If status {
        Write !, "Text of the node is "_text
        } else {
            Write !, "GetText does not return text"
        }
}

输出示例如下:

LocalName=staff
Namespace=
NamespaceIndex=
Nil=0
NodeData=staff
NodeId=1
NodeType=e
QName=staff
HasChildNodes returns 1
GetNumberAttributes returns 5
GetText does not return text

6.6 检查属性的基本方法

您可以使用以下%XML.Node方法来检查当前节点的属性。另请参见检查属性的其他方法。

  • AttributeDefined() — 如果当前元素具有给定名称的属性,则返回非零(true)。

  • FirstAttributeName() — 返回当前元素的第一个属性的属性名称。

  • GetAttributeValue() — 返回给定属性的值。如果元素没有该属性,则该方法将返回null。

  • GetNumberAttributes() — 返回当前元素的属性数。

  • LastAttributeName() —返回当前元素的最后一个属性的属性名称。

  • NextAttributeName() — 给定一个属性名称,无论指定的属性是否有效,此方法都会按排序规则顺序返回下一个属性的名称。

  • PreviousAttributeName() — 给定一个属性名称,无论指定的属性是否有效,此方法都会按排序规则顺序返回上一个属性的名称。

以下示例遍历给定节点中的属性,并编写一个简单的报告:

ClassMethod ShowAttributes(node as %XML.Node) 
{
    Set count=node.GetNumberAttributes()
    Write !, "Number of attributes: ", count
    Set first=node.FirstAttributeName()
    Write !, "First attribute is: ", first
    Write !, "   Its value is: ",node.GetAttributeValue(first)
    Set next=node.NextAttributeName(first)

    For i=1:1:count-2 {
        Write !, "Next attribute is: ", next
        Write !, "   Its value is: ",node.GetAttributeValue(next)
        Set next=node.NextAttributeName(next)
        }
    Set last=node.LastAttributeName()
    Write !, "Last attribute is: ", last
    Write !, "   Its value is: ",node.GetAttributeValue(last)
}

考虑以下示例XML文档:

<?xml version="1.0"?>
<staff attr1="first" attr2="second" attr3="third" attr4="fourth" attr5="fifth">
  <doc>
    <name>David Marston</name>
  </doc>
</staff>

如果将此文档的第一个节点传递给示例方法,则会看到以下输出:

Number of attributes: 5
First attribute is: attr1
   Its value is: first
Next attribute is: attr2
   Its value is: second
Next attribute is: attr3
   Its value is: third
Next attribute is: attr4
   Its value is: fourth
Last attribute is: attr5
   Its value is: fifth

6.7 检查属性的其他方法

本节讨论可以用于获取任何属性的名称、值、命名空间、QName和值命名空间的方法。这些方法分组如下:

  • 只使用属性名称的方法
  • 使用属性名称和命名空间的方法

注:

在XML标准中,一个元素可以包括多个具有相同名称的属性,每个属性都在不同的命名空间中。然而,在InterSystems IRIS XML中,这是不受支持的。

另请参见检查属性的基本方法。

6.7.1 仅使用属性名称的方法

使用以下方法获取有关属性的信息。

GetAttribute()

method GetAttribute(attributeName As %String, 
                    ByRef namespace As %String, 
                    ByRef value As %String, 
                    ByRef valueNamespace As %String)

返回给定属性的数据。此方法通过引用返回以下值:

  • namespace是来自属性的QName的命名空间URI。

  • value是属性值。

  • valueNamespace是该值所属的命名空间URI。例如,考虑以下属性:

    xsi:type="s:string"
    

    该属性的值是字符串,并且该值在其他地方以前缀s声明的命名空间中。假设本文档的早期部分包括以下命名空间声明:

    xmlns:s="http://www.w3.org/2001/XMLSchema" 
    

    在这种情况下,valueNamespace将为“http://www.w3.org/2001/XMLSchema".

GetAttributeNamespace()

method GetAttributeNamespace(attributeName As %String) as %String

​ 从名为attributeName的属性的QName返回当前元素的命名空间URI。

GetAttributeQName()

method GetAttributeQName(attributeName As %String) as %String

​ 返回给定属性的QName。

GetAttributeValue()

method GetAttributeValue(attributeName As %String) as %String

​ 返回给定属性的值。

GetAttributeValueNamespace()

method GetAttributeValueNamespace(attributeName As %String) as %String

​ 返回给定属性的值的命名空间。

6.7.2 使用属性名称和命名空间的方法

要同时使用属性的名称和名称空间来获取有关属性的信息,请使用以下方法:

GetAttributeNS()

method GetAttributeNS(attributeName As %String, 
                      namespace As %String, 
                      ByRef value As %String, 
                      ByRef valueNamespace As %String)

返回给定属性的数据,其中attributeName和namespace指定感兴趣的属性。此方法通过引用返回以下数据:

  • value是属性值。

  • valueNamespace是该值所属的命名空间URI。例如,考虑以下属性:

    xsi:type="s:string"
    

    该属性的值是字符串,并且该值在其他地方以前缀s声明的命名空间中。假设本文档的早期部分包括以下命名空间声明:

    xmlns:s="http://www.w3.org/2001/XMLSchema" 
    

    在这种情况下,valueNamespace将为“http://www.w3.org/2001/XMLSchema".

GetAttributeQNameNS()

method GetAttributeQNameNS(attributeName As %String, 
                           namespace As %String)
                           as %String

​ 返回给定属性的QName,其中attributeName和namespace指定感兴趣的属性。

GetAttributeValueNS()

method GetAttributeValueNS(attributeName As %String, 
                           namespace As %String) 
                           as %String

​ 返回给定属性的值,其中attributeName和namespace指定感兴趣的属性。

GetAttributeValueNamespaceNS

method GetAttributeValueNamespaceNS(attributeName As %String, 
                                    namespace As %String) 
                                    as %String

​ 返回给定属性值的命名空间,其中attributeName和namespace指定感兴趣的属性。

6.8 创建或编辑DOM

要创建DOM或修改现有DOM,请使用以下方法%XML.Document

CreateDocument()

classmethod CreateDocument(localName As %String, 
                           namespace As %String) 
                           as %XML.Document 

​ 返回%XML.Document的仅由根元素组成的新实例。

AppendCharacter()

method AppendCharacter(text As %String)

​ 将新的字符数据节点追加到此元素节点的子节点列表中。当前节点指针不变;该节点仍然是附加子节点的父节点。

AppendChild()

method AppendChild(type As %String)

​ 将新节点追加到此节点的子节点列表中。当前节点指针不变;该节点仍然是附加子节点的父节点。

AppendElement()

method AppendElement(localName As %String, 
                     namespace As %String, 
                     text As %String)

AppendNode()

method AppendNode(sourceNode As %XML.Node) as %Status

​ 附加指定节点的副本作为此节点的子节点。要复制的节点可以来自任何文档。当前节点指针不变。此节点仍然是附加子节点的父节点。

AppendTree()

method AppendTree(sourceNode As %XML.Node) as %Status

​ 附加指定节点的副本,包括其所有子节点,作为此节点的子节点。要复制的树可以来自任何文档,但此节点可能不是源节点的后代。当前节点指针不变。此节点仍然是附加子节点的父节点。

InsertNamespace()

method InsertNamespace(namespace As %String)

​ 将给定的命名空间URI添加到文档中。

InsertCharacter()

method InsertCharacter(text as %String, ByRef child As %String, Output sc As %Status) as %String

​ 插入一个新的字符数据节点作为该节点的子节点。新的字符数据正好插入到指定的子节点之前。子参数是子节点的节点ID;它是通过引用传递的,从而可以在插入之后对其进行更新。将返回插入节点的nodeId。当前节点指针不变。

InsertNode()

method InsertNode(sourceNode As %XML.Node, ByRef child As %String, Output sc As %Status) as %String

​ 插入指定节点的副本作为此节点的子节点。要复制的节点可以来自任何文档。新节点正好插入到指定的子节点之前。子参数是子节点的节点ID;它是通过引用传递的,从而可以在插入之后对其进行更新。将返回插入节点的nodeId。当前节点指针不变。

InsertTree()

method InsertTree(sourceNode As %XML.Node, ByRef child As %String, Output sc As %Status) as %String

​ 插入指定节点(包括其子节点)的副本作为此节点的子节点。要复制的树可以来自任何文档,但此节点可能不是源节点的后代。新节点正好插入到指定的子节点之前。子参数是子节点的节点ID;它是通过引用传递的,从而可以在插入之后对其进行更新。将返回插入节点的nodeId。当前节点指针不变。

Remove()

method Remove()

​ 删除当前节点并使其父节点成为当前节点。

RemoveAttribute()

method RemoveAttribute(attributeName As %String)

​ 删除给定的属性。

RemoveAttributeNS()

method RemoveAttributeNS(attributeName As %String, 
                         namespace As %String)

​ 删除给定的属性,其中attributeName和namespace指定感兴趣的属性。

ReplaceNode()

method ReplaceNode(sourceNode As %XML.Node) as %Status

​ 用指定节点(包括其所有子节点)的副本替换节点。要复制的树可以来自任何文档,但不能是源节点的后代。当前节点指针不变。

ReplaceTree()

method ReplaceTree(sourceNode As %XML.Node) as %Status

​ 用指定节点(包括其所有子节点)的副本替换节点。要复制的树可以来自任何文档,但不能是源节点的后代。当前节点指针不变。

SetAttribute()

method SetAttribute(attributeName As %String, 
                    namespace As %String = "", 
                    value As %String = "", 
                    valueNamespace As %String = "")

设置当前元素的属性的数据。在这里:

  • attributeName是属性的名称。
  • namespace是此元素的名为attributeName的属性的QName中的命名空间URI。
  • value是属性值。
  • valueNamespace是当属性值的形式为“prefix:value”时与前缀对应的命名空间URI。

6.9 从DOM编写XML输出

您可以序列化DOM或DOM的节点并生成XML输出。要执行此操作,请使用以下%XML.Writer方法:

Document()

method Document(document As %XML.Document) as %Status

​ 给定%XML.Document的实例,此方法将文档写入当前指定的输出目标。

DocumentNode()

method DocumentNode(document As %XML.Node) as %Status

​ 给定一个%XML.Node实例,此方法将节点写入当前指定的输出目标。

Tree()

method Tree(node As %XML.Node) as %Status

​ 给定一个%XML.Node实例,此方法将节点及其子体树写入当前指定的输出目标。

有关指定输出目标和设置%XML.Writer的属性的信息,请参阅从对象写入XML输出。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值