%XML.TextReader の使用
%XML.TextReaderOpens in a new tab クラスを使用すると、InterSystems IRIS® データ・プラットフォーム・オブジェクトに直接マップされているかどうかに関係なく、簡潔で容易な方法で任意の XML ドキュメントを読み取ることができます。具体的には、このクラスを使用すると、適格な形式の XML ドキュメントをナビゲートし、その中の情報 (要素、属性、コメント、ネームスペース URI など) を表示できます。このクラスは、DTD、もしくは XML スキーマを基にした、ドキュメントの完全な検証も提供します。ただし、%XML.ReaderOpens in a new tab と異なり、%XML.TextReaderOpens in a new tab には DOM を返す方法が用意されていません。DOM が必要な場合は、"オブジェクトへの XML のインポート" を参照してください。
使用するどの XML ドキュメントの XML 宣言にも、そのドキュメントの文字エンコードを明記する必要があります。これにより、ドキュメントが宣言どおりにエンコードされます。文字エンコードが宣言されていない場合は、"入出力の文字エンコード" で説明されている既定値が使用されます。これらの既定値が正しくない場合は、XML 宣言を修正して、実際に使用されている文字セットを指定するようにします。
任意の XML の読み取り
InterSystems IRIS オブジェクト・クラスとのリレーションシップが必ずしもあるとは限らない任意の XML ドキュメントを読み取るには、%XML.TextReaderOpens in a new tab クラスのメソッドを呼び出します。これにより、ドキュメントを開き、テキスト・リーダ・オブジェクトとして一時的な格納場所にロードします。テキスト・リーダ・オブジェクトには、ナビゲート可能なノードのツリーが含まれ、そのそれぞれにソース・ドキュメントについての情報が含まれています。そのため、記述したメソッドでドキュメントをナビゲートし、ドキュメントに関する情報を検出できます。このオブジェクトのプロパティは、ドキュメント内の現在の場所に応じて、そのドキュメントに関する情報を提示します。検証エラーがある場合、それらのエラーはツリー内のノードとしても表示できます。
全体構造
メソッドは以下の操作の一部またはすべてを実行する必要があります。
-
以下のメソッドのいずれかの最初の引数を使用して、ドキュメント・ソースを指定します。
メソッド 最初の引数 ParseFile() 完全なパスを含むファイル名ファイル名およびパスは ASCII 文字のみを含む必要があります。 ParseStream() ストリーム ParseString() 文字列 ParseURL() URL どのような場合でも、ソース・ドキュメントは、適格な XML ドキュメント、つまり、XML 構文の基本的な規約に従ったドキュメントである必要があります。これらのメソッドはそれぞれ、結果が成功だったかどうかを示すステータス ($$$OK または失敗コード) を返します。通常のメカニズムでステータスをテストできます。特に、$System.Status.DisplayError(status) を使用して、エラー・メッセージのテキストを表示できます。
メソッドは $$$OK を返す場合、これらのメソッドのそれぞれに対し、参照 (2 番目の引数) によって、XML ドキュメント内の情報を含むテキスト・リーダ・オブジェクトを返します。
引数をさらに追加すると、エンティティの解析、検証、検出された項目などを制御できます。"解析メソッドの引数リスト" を参照してください。
-
解析メソッドで返されたステータスを確認し、必要に応じて実行を中止します。
解析メソッドが $$$OK を返した場合、テキスト・リーダ・オブジェクトはソース XML ドキュメントに対応しています。このオブジェクトはナビゲートできます。
ドキュメントには多くの場合、"element"、"endelement"、"startprefixmapping" などのノードが含まれています。"ノード・タイプ" に、ノード・タイプの一覧が記載されています。
Important:どのような検証エラーが発生した場合でも、ドキュメントには "error" ノードまたは "warning" ノードが含まれています。そのようなノードがないか、コードで確認する必要があります。"検証の実行" を参照してください。
-
以下のインスタンス・メソッドのいずれかを使用して、ドキュメントの読み取りを開始します。
-
ドキュメントの最初のノードへ移動するには、Read() を使用します。
-
特定のタイプの最初の要素へ移動するには、ReadStartElement() を使用します。
-
"chars" の最初のノードへ移動するには、MoveToContent() を使用します。
"ドキュメントのナビゲート" を参照してください。
-
-
このノードで関係するプロパティの値があれば、それを取得します。利用可能なプロパティには、Name、Value、Depth などがあります。"ノード・プロパティ" を参照してください。
-
必要に応じてドキュメントのナビゲートおよびプロパティ値の取得を続けます。
現在のノードが要素の場合、MoveToAttributeIndex() または MoveToAttributeName() メソッドを使用して、要素の属性にフォーカスを移動できます。要素に戻るには、該当する場合は MoveToElement() を使用します。
-
必要に応じて、Rewind() メソッドを使用して、ドキュメントの最初 (最初のノードの前) に戻ります。これは、ソース内を後退できる唯一のメソッドです。
メソッドの実行後、テキスト・リーダは消滅し、関連する一時格納場所もすべてクリーンアップされます。
例 1
ここでは、任意の XML ファイルを読み取り、各ノードのシーケンス番号、タイプ、名前、および値を表示する単純なメソッドを示します。
ClassMethod WriteNodes(myfile As %String)
{
set status=##class(%XML.TextReader).ParseFile(myfile,.textreader)
//check status
if $$$ISERR(status) {do $System.Status.DisplayError(status) quit}
//iterate through document, node by node
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
}
}
}
この例は、以下を実行します。
-
ParseFile() クラス・メソッドを呼び出します。このメソッドはソース・ファイルを読み取り、テキスト・リーダ・オブジェクトを生成して、変数 doc 内でそのオブジェクトを参照によって返します。
-
ParseFile() が成功した場合、このメソッドは Read() メソッドを実行して、ドキュメント内で次のノードをそれぞれ検索します。
-
各ノードについて、このメソッドは、そのノードのシーケンス番号、ノード・タイプ、ノード名 (存在する場合)、ノード・パス、およびノード値 (存在する場合) が含まれた出力行を記述します。現在のデバイスに出力されます。
以下の例のソース・ドキュメントを考えてみます。
<?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="xyz">Willeke,Clint B.</Name>
<DOB>1925-10-01</DOB>
</s01:Person>
</Root>
このソース・ドキュメントについては、前述のメソッドで以下の出力が生成されます。
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: Willeke,Clint B.
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: 1925-10-01
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.TextReaderOpens in a new tab クラスはコメントを無視します。この変更の詳細は、"解析メソッドの引数リスト" で説明します。
例 2
以下の例では、XML ファイルを読み取り、その中の各要素をリスト表示します。
ClassMethod ShowElements(myfile As %String)
{
set status = ##class(%XML.TextReader).ParseFile(myfile,.textreader)
//check status
if $$$ISERR(status) {do $System.Status.DisplayError(status) quit}
//iterate through document, node by node
while textreader.Read()
{
if (textreader.NodeType = "element")
{
write textreader.Name,!
}
}
}
このメソッドは、NodeType プロパティを使用して、各ノードのタイプをチェックします。そのノードが要素の場合、メソッドはその名前を現在のデバイスに出力します。前述の XML ソース・ドキュメントについては、このメソッドで以下の出力が生成されます。
Root
s01:Person
Name
DOB
ノード・タイプ
ドキュメントのノードはそれぞれ、以下のタイプのいずれかになります。
タイプ | 説明 |
---|---|
"attribute" | XML 属性 |
"chars" | 文字一式 (要素のコンテンツなど)
%XML.TextReaderOpens in a new tab クラスは、他のノード・タイプ ("CDATA"、"EntityReference"、および "EndEntity") を認識しますが、それらを "chars" に自動的に変換します。 |
"comment" | XML コメント |
"element" | XML 要素の先頭 |
"endelement" | XML 要素の終了 |
"endprefixmapping" | ネームスペースが宣言されているコンテキストの終了 |
"entity" | XML エンティティ |
"error" | パーサで検出された検証エラー。"検証の実行" を参照してください。 |
"ignorablewhitespace" | 混在するコンテンツ・モデルのマークアップ間にある空白 |
"processinginstruction" | XML 処理命令 |
"startprefixmapping" | ネームスペースを含むまたは含まない可能性がある、XML ネームスペース宣言 |
"warning" | パーサで検出された検証の警告。"検証の実行" を参照してください。 |
1 つの XML 要素が複数のノードで構成されていることに注意してください。例えば、以下の XML フラグメントを考えてみます。
<Person>
<Name>Willeke,Clint B.</Name>
<DOB>1925-10-01</DOB>
</Person>
SAX パーサは、この XML を以下のノードのセットとして表示します。
ノード番号 | ノードのタイプ | ノード名 (存在する場合) | ノードの値 (存在する場合) |
---|---|---|---|
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> 要素は、element ノード、chars ノード、および endelement ノードの 3 つのノードであると見なされることに注意してください。また、この要素のコンテンツは、chars ノードの値としてのみ使用できることにも注意してください。
ノード・プロパティ
%XML.TextReaderOpens in a new tab クラスは XML ドキュメントを解析し、ドキュメントのコンポーネントに対応するノードのセットで構成されるテキスト・リーダ・オブジェクトを作成します。ノード・タイプについては、"ドキュメント・ノード" を参照してください。
別のノードにフォーカスを変更すると、そのテキスト・リーダ・オブジェクトのプロパティが更新され、現在調べているノードについての情報が含められます。ここでは、%XML.TextReaderOpens in a new tab クラスのすべてのプロパティについて説明します。
現在のノードが要素または属性の場合、このプロパティは、要素の属性の番号を示します。任意の要素内で最初の属性の番号は 1 となります。
その他のタイプのノードでは、このプロパティは 0 になります。
ドキュメント内での現在のノードの深さを示します。ルート要素の深さは 1 です。ルート要素外の項目の深さは 0 です。属性は、それが属する要素と同じ深さにあることに注意してください。同様に、エラーまたは警告は、そのエラーまたは警告を引き起こした項目と同じ深さになります。
リーダがソース・ドキュメントの末尾に到達した場合は True、それ以外の場合は False です。
現在のノードが要素の場合、その要素に属性があれば、このプロパティは True です (属性がなければ False です)。現在のノードが属性の場合、このプロパティは True です。
その他のタイプのノードでは、このプロパティは False になります。
現在のノードが値を持つタイプのノードの場合 (その値が Null であっても)、True です。それ以外の場合、このプロパティは False です。具体的には、このプロパティは以下のタイプのノードでは True となります。
-
attribute
-
chars
-
comment
-
entity
-
ignorablewhitespace
-
processinginstruction
-
startprefixmapping
エラーおよび警告のタイプのノードについては、それらのノード・タイプに値があっても、HasValue は False となることに注意してください。
現在のノードが要素であり、空白である場合には True です。それ以外の場合、このプロパティは False です。
attribute、element、または endelement のタイプのノードの場合、これは現在の要素または属性の名前からネームスペースの接頭語を除いたものとなります。その他すべてのタイプのノードでは、このプロパティは Null になります。
ノードのタイプに応じた、現在のノードの完全修飾名です。以下のテーブルに詳細を示します。
ノード・タイプ | 名前と例 |
---|---|
attribute | 属性の名前。例えば、次のような属性の場合、
groupID="GX078" Name は次のようになります。 groupID |
element
または endelement |
要素の名前。例えば、次のような要素の場合、
<s01:Person groupID="GX078">...</s01:Person> Name は次のようになります。 s01:Person |
entity | エンティティの名前 |
startprefixmapping
または endprefixmapping |
接頭語 (存在する場合)。例えば、次のようなネームスペース宣言の場合、
xmlns:s01="http://www.root.org" Name は次のようになります。 s01 別の例では、次のようなネームスペース宣言の場合、 xmlns="http://www.root.org" Name は Null になります。 |
processinginstruction | 処理命令のターゲット。例えば、次のような処理命令の場合、
<?xml-stylesheet type="text/css" href="mystyles.css"?> Name は次のようになります。 xml-stylesheet |
その他すべてのタイプ | null |
attribute、element、または endelement のタイプのノードの場合、これは属性または要素が属するネームスペース (存在する場合) となります。その他すべてのタイプのノードでは、このプロパティは Null になります。
現在のノードのタイプ。"ドキュメント・ノード" を参照してください。
要素のパス。例えば、以下の XML ドキュメントを考えてみます。
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="mystyles.css"?>
<s01:Root xmlns:s01="http://www.root.org" xmlns="www.default.org">
<Person>
<Name>Willeke,Clint B.</Name>
<DOB>1925-10-01</DOB>
<GroupID>U3577</GroupID>
<Address xmlns="www.address.org">
<City>Newton</City>
<Zip>56762</Zip>
</Address>
</Person>
</s01:Root>
City 要素の Path プロパティは /s01:Root/Person/Address/City です。他の要素も同様に処理されます。
テキスト・リーダ・オブジェクトの全体の状態を、以下のいずれかで示します。
-
"Initial" は、Read() メソッドがまだ呼び出されていないことを示します。
-
"Interactive" は、Read() メソッドが少なくとも 1 回呼び出されたことを示します。
-
"EndOfFile" は、ファイルの末尾に達したことを示します。
ノードのタイプに応じた、現在のノードの値 (存在する場合) です。以下のテーブルに詳細を示します。
ノード・タイプ | 値と例 |
---|---|
attribute | 属性の値例えば、次のような属性の場合、
groupID="GX078" Value は次のようになります。 GX078 |
chars | テキスト・ノードのコンテンツ例えば、次のような要素の場合、
<DOB>1925-10-01</DOB> chars ノードでは、Value は次のようになります。 1925-10-01 |
comment | コメントのコンテンツ例えば、次のようなコメントの場合、
<!--Comment here--> Value は次のようになります。 Comment here |
entity | エンティティの定義 |
error | エラー・メッセージ。例は、"検証の実行" を参照してください。 |
ignorablewhitespace | 空白のコンテンツ |
processinginstruction | ターゲット以外の処理命令全体のコンテンツ例えば、次のような処理命令の場合、
<?xml-stylesheet type="text/css" href="mystyles.css"?> Value は次のようになります。 type="text/css" href="mystyles.css"? |
startprefixmapping | 接頭語の後にスペース文字が 1 つ、その後に URI が続きます。例えば、次のようなネームスペース宣言の場合、
xmlns:s01="http://www.root.org" Value は次のようになります。 s01 http://www.root.org |
warning | 警告メッセージ。例は、"検証の実行" を参照してください。 |
その他すべてのタイプ (element を含む) | null |
ドキュメント内のこのノードのシーケンス番号。最初のノードの番号は 1 です。属性には、それが属する要素と同じシーケンス番号が割り当てられていることに注意してください。
解析メソッドの引数リスト
ドキュメント・ソースを解析するには、テキスト・リーダの ParseFile()、ParseStream()、ParseString()、または ParseURL() メソッドを使用します。どのような場合でも、ソース・ドキュメントは、適格な XML ドキュメント、つまり、XML 構文の基本的な規約に従ったドキュメントである必要があります。これらのメソッドでは、最初の 2 つの引数のみが必要となります。参考までに、これらのメソッドの引数を以下に順番に示します。
-
Filename、Stream、String、または URL — ドキュメント・ソース。
ParseFile() では、Filename 引数には ASCII 文字のみを含む必要があります。
-
TextReader — テキスト・リーダ・オブジェクト。メソッドが $$$OK を返す場合に、出力パラメータとして返されます。
-
Resolver — ソースの解析時に使用されるエンティティ・リゾルバ。詳細は、"SAX パーサの使用法のカスタマイズ" の "カスタム・エンティティの解析実行" を参照してください。
-
Flags — SAX パーサによる検証と処理を制御するフラグまたはフラグの組み合わせ。詳細は、"SAX パーサの使用法のカスタマイズ" の "パーサ・フラグの設定" を参照してください。
-
Mask — XML ソース内の目的の項目を指定するためのマスク。詳細は、"SAX パーサの使用法のカスタマイズ" の "イベント・マスクの指定" を参照してください。
Tip:%XML.TextReaderOpens in a new tab の解析メソッドでは、既定のマスクは $$$SAXCONTENTEVENTS です。これはコメントを無視することに注意してください。可能性のあるタイプのノードをすべて解析するには、この引数に $$$SAXALLEVENTS を使用します。これらのマクロは、%occSAX.inc インクルード・ファイルで定義します。
-
SchemaSpec — ドキュメント・ソースの検証の基準となるスキーマ仕様。この引数は、ネームスペース/URL のペアをコンマで区切って指定したリストを含む文字列です。
"namespace URL,namespace URL"
ここで、namespace はスキーマに使用する XML ネームスペースで、URL はスキーマ・ドキュメントの位置を表す URL です。ネームスペースと URL の値の間は、1 つの空白文字で区切られています。
-
KeepWhiteSpace — 空白を保持するかどうかを指定するオプション。
-
pHttpRequest — (ParseURL() メソッドのみ) %Net.HttpRequestOpens in a new tab のインスタンスとしての、Web サーバへの要求。既定では、システムは %Net.HttpRequestOpens in a new tab の新規インスタンスを作成してそれを使用しますが、代わりに、%Net.HttpRequestOpens in a new tab の別のインスタンスで要求を行うことができます。これは、既存の %Net.HttpRequestOpens in a new tab があり、プロキシおよびその他のプロパティが既に設定されている場合に役立ちます。このオプションは、http のタイプの (file や ftp などではない) URL にのみ適用されます。
%Net.HttpRequestOpens in a new tab の詳細は、"インターネット・ユーティリティの使用法" を参照してください。または、%Net.HttpRequestOpens in a new tab のクラス・ドキュメントを参照してください。
検証の実行
既定では、ソース・ドキュメントは指定された任意の DTD またはスキーマ・ドキュメントに対して検証されます。ドキュメントに DTD セクションが含まれる場合、そのドキュメントはその DTD に対して検証されます。代わりに、スキーマ・ドキュメントとの照合で検証するには、"解析メソッドの引数リスト" の説明にあるように、ParseFile()、ParseStream()、ParseString()、または ParseURL() の引数リストで目的のスキーマを指定します。
ほとんどのタイプの検証の問題は致命的ではなく、エラーまたは警告のいずれかを発生させます。具体的には、タイプが "error" または "warning" のノードが、ドキュメント・ツリーのエラーが発生した場所に自動的に追加されます。こうしたノードには、他のタイプのノードと同様に移動し、調査できます。
例えば、以下の XML ドキュメントを考えてみます。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Root [
<!ELEMENT Root (Person)>
<!ELEMENT Person (#PCDATA)>
]>
<Root>
<Person>Smith,Joe C.</Person>
</Root>
この場合、検証エラーは予期されません。このトピックで前述したメソッド例 WriteNodes() を思い出してください。そのメソッドを使用してこのドキュメントを読み取る場合、出力は以下のようになります。
Node 1 is a(n) element named: Root
and has no value
Node 2 is a(n) ignorablewhitespace and has no name
with value:
Node 3 is a(n) element named: Person
and has no value
Node 4 is a(n) chars and has no name
with value: Smith,Joe C.
Node 5 is a(n) endelement named: Person
and has no value
Node 6 is a(n) ignorablewhitespace and has no name
with value:
Node 7 is a(n) endelement named: Root
and has no value
一方、ファイルは以下のようになるとします。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Root [
<!ELEMENT Root (Person)>
<!ELEMENT Person (#PCDATA)>
]>
<Root>
<Employee>Smith,Joe C.</Employee>
</Root>
この場合、<Employee> 要素が DTD セクションで宣言されていないので、エラーが予想されます。ここで、メソッド例 WriteNodes() を使用してこのドキュメントを読み取る場合、出力は以下のようになります。
Node 1 is a(n) element named: Root
and has no value
Node 2 is a(n) ignorablewhitespace and has no name
with value:
Node 3 is a(n) error and has no name
with value: Unknown element 'Employee'
while processing c:/TextReader/docwdtd2.txt at line 7 offset 14
Node 4 is a(n) element named: Employee
and has no value
Node 5 is a(n) chars and has no name
with value: Smith,Joe C.
Node 6 is a(n) endelement named: Employee
and has no value
Node 7 is a(n) ignorablewhitespace and has no name
with value:
Node 8 is a(n) error and has no name
with value: Element 'Employee' is not valid for content model: '(Person)'
while processing c:/TextReader/docwdtd2.txt at line 8 offset 8
Node 9 is a(n) endelement named: Root
and has no value
"SAX パーサの使用法のカスタマイズ" の "パーサ・フラグの設定" も参照してください。
例 : ネームスペースのレポート
次のサンプルのメソッドでは、任意の XML ファイルを読み取り、それぞれの要素および属性が属するネームスペースを示します。
ClassMethod ShowNamespacesInFile(filename As %String)
{
Set status = ##class(%XML.TextReader).ParseFile(filename,.textreader)
//check status
If $$$ISERR(status) {do $System.Status.DisplayError(status) quit}
//iterate through document, node by node
While textreader.Read()
{
If (textreader.NodeType = "element")
{
Write !,"The element ",textreader.LocalName
Write " is in the namespace ",textreader.NamespaceUri
}
If (textreader.NodeType = "attribute")
{
Write !,"The attribute ",textreader.LocalName
Write " is in the namespace ",textreader.NamespaceUri
}
}
}
ターミナルで使用すると、このメソッドは以下のような出力を生成します。
The element Person is in the namespace www://www.person.com
The element Name is in the namespace www://www.person.com
次のバリエーションでは、XML 対応オブジェクトを受け取り、それをストリームに書き込んで、そのストリームを使用して同じタイプのレポートを生成しています。
ClassMethod ShowNamespacesInObject(obj)
{
set writer=##class(%XML.Writer).%New()
set str=##class(%GlobalCharacterStream).%New()
set status=writer.OutputToStream(str)
if $$$ISERR(status) {do $System.Status.DisplayError(status) quit ""}
//write to the stream
set status=writer.RootObject(obj)
if $$$ISERR(status) {do $System.Status.DisplayError(status) quit }
Set status = ##class(%XML.TextReader).ParseStream(str,.textreader)
//check status
If $$$ISERR(status) {do $System.Status.DisplayError(status) quit}
//iterate through document, node by node
While textreader.Read()
{
If (textreader.NodeType = "element")
{
Write !,"The element ",textreader.LocalName
Write " is in the namespace ",textreader.NamespaceUri
}
If (textreader.NodeType = "attribute")
{
Write !,"The attribute ",textreader.LocalName
Write " is in the namespace ",textreader.NamespaceUri
}
}
}