XML ドキュメントの DOM 表現
%XML.DocumentOpens in a new tab クラスと %XML.NodeOpens in a new tab クラスを使用して、任意の XML ドキュメントを DOM (ドキュメント・オブジェクト・モデル) として表現できます。その後、このオブジェクトをナビゲートして変更できます。新しい DOM を作成してオブジェクトに追加することもできます。以下の項目について説明します。
使用する任意の XML ドキュメントの XML 宣言にはそのドキュメントの文字エンコードを明記する必要があり、明記しておけば、ドキュメントは宣言どおりにエンコードされるようになります。文字エンコードが宣言されていない場合は、このドキュメント内の前述の “入出力の文字エンコード” で説明されている既定値が使用されます。これらの既定値が正しくない場合は、XML 宣言を修正して、実際に使用されている文字セットを指定するようにします。
DOM として XML ドキュメントを開く
既存の XML ドキュメントを DOM として使用するために開くには、以下の手順を実行します。
-
%XML.ReaderOpens in a new tab クラスのインスタンスを作成します。
-
必要に応じて、このインスタンスの Format プロパティを指定して、インポートするファイルの形式を指定します。
既定では、XML ファイルはリテラル形式と想定されます。ファイルが SOAP でエンコードされた形式の場合は、そのように明記して、ファイルを正しく読み取れるようにする必要があります。
“Caché オブジェクトへの XML のインポート” の章の “リーダ・プロパティ” を参照してください。
Correlate() と Next() を使用していない場合、このプロパティには何の効果もなくなります。
-
ソースを開きます。そのためには、%XML.ReaderOpens in a new tab の次のメソッドのいずれかを使用します。
-
OpenFile() — ファイルを開きます。
-
OpenStream() — ストリームを開きます。
-
OpenString() — 文字列を開きます。
-
OpenURL() — URL を開きます。
いずれの場合も、オプションでメソッドに 2 番目の引数を指定して、Format プロパティの値をオーバーライドすることができます。
-
-
DOM である Document プロパティにアクセスします。このプロパティは %XML.DocumentOpens in a new tab のインスタンスであり、ドキュメント全体についての情報を見つけるのに使用できるメソッドを提供します。例えば、CountNamespace() は DOM で使用されるネームスペースの総数を返します。
または、XML ドキュメントを格納したストリームがある場合は、%XML.DocumentOpens in a new tab の GetDocumentFromStream() メソッドを呼び出します。これにより %XML.DocumentOpens in a new tab のインスタンスが返されます。
例 1 : ファイルの DOM への変換
例えば、以下のメソッドで XML ファイルを読み取り、そのドキュメントを表す %XML.DocumentOpens in a new tab のインスタンスを返します。
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
}
例 2 : オブジェクトの DOM への変換
以下のメソッドで OREF を受け入れ、そのオブジェクトを表す %XML.DocumentOpens in a new tab のインスタンスを返します。このメソッドでは、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=$zobjclassmethod(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
}
DOM のネームスペースの取得
Caché で XML ドキュメントを読み取り、DOM を作成するとき、ドキュメント内で使用されるすべてのネームスペースが識別され、それぞれにインデックス番号が割り当てられます。
%XML.DocumentOpens in a new tab クラスのインスタンスは、ドキュメント内のネームスペースについての情報を見つけるために使用できる以下のメソッドを提供します。
ドキュメント内のネームスペースの数を返します。
指定されたネームスペースに対応するインデックスを返します。
指定されたインデックスの 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)
}
}
この章で後述する “現在のノードについての情報の取得” も参照してください。
DOM ノード・タイプ
%XML.DocumentOpens in a new tab クラスと %XML.NodeOpens in a new tab クラスは、以下の DOM ノード・タイプを認識します。
-
要素 ($$$xmlELEMENTNODE)
これらのマクロは、%xml.DOM.inc インクルード・ファイルで定義します。
-
テキスト ($$$xmlTEXTNODE)
-
空白 ($$$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 | メモ |
---|---|---|---|
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 | このノードは、2 番目の <member> ノードの子です。 |
1,45 | $$$xmlWHITESPACENODE | このノードは、<team> ノードの子です。 | |
1,49 | $$$xmlELEMENTNODE | member | このノードは、<team> ノードの子です。 |
4,45 | $$$xmlTEXTNODE | Daniel Jackson | このノードは、3 番目の <member> ノードの子です。 |
1,53 | $$$xmlWHITESPACENODE | このノードは、<team> ノードの子です。 |
ノード・タイプやローカル名などの詳細へのアクセスについては、次のセクションを参照してください。
現在のノードについての情報の取得
%XML.NodeOpens in a new tab の以下の文字列プロパティは、現在のノードについての情報を提供します。いずれの場合にも、現在のノードがないとエラーがスローされます。
現在の要素ノードのローカル名。別のタイプのノードでこのプロパティにアクセスしようとすると、エラーがスローされます。
現在の要素ノードのネームスペース URI。別のタイプのノードでこのプロパティにアクセスしようとすると、エラーがスローされます。
現在の要素ノードのネームスペースのインデックス。
Caché で XML ドキュメントを読み取り、DOM を作成するとき、ドキュメント内で使用されるすべてのネームスペースが識別され、それぞれにインデックス番号が割り当てられます。
別のタイプのノードでこのプロパティにアクセスしようとすると、エラーがスローされます。
この要素ノードに対して xsi:nil または xsi:null が True または 1 の場合は True になります。それ以外の場合、このプロパティは False になります。
文字ノードの値。
現在のノードの ID。別のノードに移動するために、このプロパティを設定できます。
前のセクションで説明している、現在のノードのタイプ。
要素ノードの Qname。接頭語がドキュメントで有効な場合に、XML としての出力のみに使用されます。
以下のメソッドは、現在のノードについての追加情報を提供します。
method GetText(ByRef text) as %Boolean
要素ノードのテキスト・コンテンツを取得します。テキストが返される場合、このメソッドは True を返します。この場合、実際のテキストは参照渡しの最初の引数に追加されます。
method HasChildNodes(skipWhitespace As %Boolean = 0) as %Boolean
現在のノードに子ノードがある場合に True を返します。それ以外の場合は False を返します。
method GetNumberAttributes() as %Integer
現在の要素の属性の番号を返します。属性については、この章の後半で詳細に説明しています。
例
以下の例のメソッドは、現在のノードについての情報を提供するレポートを記述します。
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
属性の検証のための基本的なメソッド
%XML.NodeOpens in a new tab の以下のメソッドを使用して、現在のノードの属性を検証できます。その他のメソッドについては、この章で後述する “属性の検証のためのその他のメソッド” も参照してください。
-
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
属性の検証のためのその他のメソッド
このセクションでは、属性の名前、値、ネームスペース、QName、および値ネームスペースを取得するのに使用できるメソッドについて説明します。これらのメソッドは以下のとおりに分類されます。
“属性の検証のための基本的なメソッド” も参照してください。
属性名のみを使用するメソッド
属性についての情報を取得するには以下のメソッドを使用します。
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"
この属性の値は string であり、この値は、別の場所で宣言され、接頭語を s とするネームスペースの中にあります。このドキュメントの既述部分に、以下のネームスペース宣言があったとします。
xmlns:s="http://www.w3.org/2001/XMLSchema"
この場合、valueNamespace は "http://www.w3.org/2001/XMLSchema" となります。
method GetAttributeNamespace(attributeName As %String) as %String
現在の要素の attributeName という名前の属性の QName から、ネームスペース URI を返します。
method GetAttributeQName(attributeName As %String) as %String
指定した属性の QName を返します。
method GetAttributeValue(attributeName As %String) as %String
指定した属性の値を返します。
method GetAttributeValueNamespace(attributeName As %String) as %String
指定した属性の値のネームスペースを返します。
属性名とネームスペースを使用するメソッド
名前とネームスペースの両方を使用して属性についての情報を取得するには、以下のメソッドを使用します。
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"
この属性の値は string であり、この値は、別の場所で宣言され、接頭語を s とするネームスペースの中にあります。このドキュメントの既述部分に、以下のネームスペース宣言があったとします。
xmlns:s="http://www.w3.org/2001/XMLSchema"
この場合、valueNamespace は "http://www.w3.org/2001/XMLSchema" となります。
method GetAttributeQNameNS(attributeName As %String,
namespace As %String)
as %String
指定した属性の QName を返します。attributeName および namespace で目的の属性を指定します。
method GetAttributeValueNS(attributeName As %String,
namespace As %String)
as %String
指定した属性の値を返します。attributeName および namespace で目的の属性を指定します。
method GetAttributeValueNamespaceNS(attributeName As %String,
namespace As %String)
as %String
指定した属性の値のネームスペースを返します。attributeName および namespace で目的の属性を指定します。
DOM の作成または編集
DOM を作成するか既存の DOM を変更するには、%XML.DocumentOpens in a new tab の以下のメソッドを使用します。
classmethod CreateDocument(localName As %String,
namespace As %String)
as %XML.Document
ルート要素のみから構成される %XML.DocumentOpens in a new tab の新しいインスタンスを返します。
method AppendCharacter(text As %String)
新しい文字データ・ノードをこの要素ノードの子のリストに追加します。現在のノードのポインタは変更されません。このノードは追加された子の親のままです。
method AppendChild(type As %String)
新しいノードをこのノードの子のリストに追加します。現在のノードのポインタは変更されません。このノードは追加された子の親のままです。
method AppendElement(localName As %String,
namespace As %String,
text As %String)
新しい要素ノードをこのノードの子のリストに追加します。テキストの引数が指定されると、文字データが新しい要素の子として追加されます。現在のノードのポインタは変更されません。このノードは追加された子の親のままです。
method AppendNode(sourceNode As %XML.Node) as %Status
このノードの子として、指定したノードのコピーを追加します。コピーするノードは、任意のドキュメントをコピー元にできます。現在のノードのポインタは変更されません。このノードは追加された子の親のままです。
method AppendTree(sourceNode As %XML.Node) as %Status
このノードの子として、指定したノードの (すべての子を含む) コピーを追加します。コピーするツリーは任意のドキュメントをコピー元にできますが、ソース・ノードの下位ノードをこのノードにすることはできません。現在のノードのポインタは変更されません。このノードは追加された子の親のままです。
method InsertNamespace(namespace As %String)
指定されたネームスペース URI をドキュメントに追加します。
method InsertCharacter(text as %String, ByRef child As %String, Output sc As %Status) as %String
このノードの子として、新しい文字データ・ノードを挿入します。新しい文字データは、指定した子ノードの直前に挿入されます。child 引数は、子ノードのノード ID です。これは参照によって渡されるため、挿入後に更新される可能性があります。挿入されたノードの NodeId が返されます。現在のノードのポインタは変更されません。
method InsertNode(sourceNode As %XML.Node, ByRef child As %String, Output sc As %Status) as %String
このノードの子として、指定したノードのコピーを挿入します。コピーするノードは、任意のドキュメントをコピー元にできます。新規ノードは、指定した子ノードの直前に挿入します。child 引数は、子ノードのノード ID です。これは参照によって渡されるため、挿入後に更新される可能性があります。挿入されたノードの NodeId が返されます。現在のノードのポインタは変更されません。
method InsertTree(sourceNode As %XML.Node, ByRef child As %String, Output sc As %Status) as %String
このノードの子として、指定したノードの (その子を含む) コピーを挿入します。コピーするツリーは任意のドキュメントをコピー元にできますが、ソース・ノードの下位ノードをこのノードにすることはできません。新規ノードは、指定した子ノードの直前に挿入します。child 引数は、子ノードのノード ID です。これは参照によって渡されるため、挿入後に更新される可能性があります。挿入されたノードの NodeId が返されます。現在のノードのポインタは変更されません。
method Remove()
現在のノードを削除し、その親を現在のノードにします。
method RemoveAttribute(attributeName As %String)
指定された属性を削除します。
method RemoveAttributeNS(attributeName As %String,
namespace As %String)
指定した属性を削除します。attributeName および namespace で目的の属性を指定します。
method ReplaceNode(sourceNode As %XML.Node) as %Status
ノードを、指定したノードのコピーで置き換えます。コピーするノードは、任意のドキュメントをコピー元にできます。現在のノードのポインタは変更されません。
method ReplaceTree(sourceNode As %XML.Node) as %Status
ノードを、指定したノードの (そのすべての子を含む) コピーで置き換えます。コピーするツリーは任意のドキュメントをコピー元にできますが、ソース・ノードの下位ノードにすることはできません。現在のノードのポインタは変更されません。
method SetAttribute(attributeName As %String,
namespace As %String = "",
value As %String = "",
valueNamespace As %String = "")
現在の要素の属性のデータを設定します。以下はその説明です。
-
attributeName は、属性の名前です。
-
namespace は、この要素の attributeName という名前の属性の QName からのネームスペース URI です。
-
value は属性値です。
-
属性値が "prefix:value" の形式である場合、valueNamespace は接頭語に相当するネームスペース URI です。
DOM からの XML 出力の記述
DOM または DOM のノードをシリアル化し、XML 出力を生成することができます。このためには、%XML.WriterOpens in a new tab の以下のメソッドを使用します。
method Document(document As %XML.Document) as %Status
%XML.DocumentOpens in a new tab のインスタンスを指定する場合、このメソッドは現在指定されている出力先にドキュメントを記述します。
method DocumentNode(document As %XML.Node) as %Status
%XML.NodeOpens in a new tab のインスタンスを指定する場合、このメソッドは現在指定されている出力先にノードを記述します。
method Tree(node As %XML.Node) as %Status
%XML.NodeOpens in a new tab のインスタンスを指定する場合、このメソッドは現在指定されている出力先にノードとその下位ツリーを記述します。
出力先の指定と %XML.WriterOpens in a new tab のプロパティの設定の詳細は、“Caché オブジェクトからの XML 出力の記述” の章を参照してください。