使用%XML.Document
和%XML.Node
,可以将任意XML文档表示为DOM(文档对象模型)。然后,您可以导航并修改这个对象。您还可以创建一个新的DOM并添加到其中。
注:
您使用的任何XML文档的XML声明都应该指示该文档的字符编码,并且该文档应该按照声明的方式进行编码。如果未声明字符编码,InterSystems IRIS将使用输入和输出的字符编码中描述的默认值。如果这些默认值不正确,请修改XML声明,使其指定实际使用的字符集。
6.1 以DOM形式打开XML文档
要打开现有的XML文档用作DOM,请执行以下操作:
-
创建
%XML.Reader
的实例。 -
(可选)指定此实例的“格式”属性,以指定要导入的文件的格式。
默认情况下,InterSystems IRIS假设XML文件是文字格式的。如果您的文件是SOAP编码的格式,则必须指出这一点,以便能够正确读取文件。
请参阅将XML导入对象中的Reader属性。
除非使用
Correlate()
和Next()
,否则此属性无效。 -
打开源数据。要执行此操作,请使用以下
%XML.Reader
方法之一:-
OpenFile() — 打开一个文件。
-
OpenStream() — 打开流。
-
OpenString() — 打开一个字符串。
-
OpenURL() — 打开一个URL。
在每种情况下,您都可以选择为方法指定第二个参数来覆盖Format属性的值。
-
-
访问
Document
属性,该属性是一个DOM。此属性是%XML.document
的一个实例,它提供了可以用来查找整个文档信息的方法。例如,CountNamespace()
返回DOM使用的命名空间总数。
或者,如果您有一个包含XML文档的流,请在调用%XML.Document
的GetDocumentFromStream()
方法。这将返回一个%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查看时,此文档由以下节点组成:
文档节点示例
NodeID | NodeType | LocalName | Notes |
---|---|---|---|
0,29 | $$$xmlELEMENTNODE | team | |
1,29 | $$$xmlWHITESPACENODE | 此节点是<team> 节点的子节点 | |
1,23 | $$$xmlELEMENTNODE | member | 此节点是<team> 节点的子节点 |
2,45 | $$$xmlTEXTNODE | Jack O’Neill | 此节点是第一个<member> 节点的子节点 |
1,37 | $$$xmlWHITESPACENODE | 此节点是<team> 节点的子节点 | |
1,41 | $$$xmlELEMENTNODE | member | 此节点是<team> 节点的子节点 |
3,45 | $$$xmlTEXTNODE | Samantha Carter | 此节点是第二个<member> 节点的子节点 |
1,45 | $$$xmlWHITESPACENODE | 此节点是<team> 节点的子节点 | |
1,49 | $$$xmlELEMENTNODE | member | 此节点是<team> 节点的子节点 |
4,45 | $$$xmlTEXTNODE | Daniel 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输出。