この項の内容は次のとおりです。
Oracle XML Parsingは、XML文書を読み取り、DOMまたはSAX APIを使用して、そのコンテンツと構造へのプログラム・アクセスを可能にします。この解析は検証モードまたは非検証モードで使用できます。
この章では、次のテクノロジを十分に理解していると想定します。
Document Object Model(DOM): DOMは、XML文書の構造を示すメモリー内ツリー表現です。
Simple API for XML(SAX): SAXは、イベントベースのXML解析の標準です。
Java API for XML Processing(JAXP): JAXPは、JavaアプリケーションでXMLを処理するための標準インタフェースです。DOM標準とSAX標準をサポートします。
Document Type Definition(DTD): XML DTDは、XML文書の有効な構造を定義します。
XMLスキーマ: DTDと同様にXMLスキーマはXML文書の有効な構造を定義します。
XML名前空間: 名前空間は要素名や属性名を識別するためのメカニズムです。
バイナリXML: 拡張性のあるDOMも拡張性のないDOMも、この形式でXML文書を保存できます。
前述のテクノロジの概要説明が必要な場合は、「はじめに」の「関連ドキュメント」にあるXMLの資料を参照してください。
DOMレベル1、レベル2およびレベル3の仕様はW3C勧告です。次のURLに、3つのレベルすべての仕様へのリンクがあります。
http://www.w3.org/DOM/DOMTR
SAXにはバージョン1.0と2.0があり、バージョン1.0は非推奨です。これはW3C仕様ではありません。次のURLに、SAXのドキュメントがあります。
http://www.saxproject.org/
XML名前空間はW3C勧告です。仕様は次のURLにあります。
http://www.w3.org/TR/REC-xml-names
JCR 1.0(JSR 170とも呼ばれます)は、アプリケーションがコンテンツ・リポジトリと対話するための標準Java APIを定義しています。
関連項目: 『Oracle XML DB開発者ガイド』 |
JAXPバージョン1.2には、XSLTフレームワークに加えて、DOMレベル2およびSAXバージョン2.0をサポートするための解析APIに対する更新と、プラッガブルな実装を特定するための改良されたスキームが含まれています。JAXPでは、XMLスキーマとXSLTコンパイラがサポートされています。次のURLに、Sun社が作成したJAXP仕様があります。
http://java.sun.com/xml/downloads/jaxp.html
XMLノードへのDOMストリーム・アクセスは、PL/SQLおよびJavaのAPIによって実行されます。XML文書内のノードは64Kバイトを大幅に超えます。このため、JPEG、Word、PDF、RTFおよびHTML文書を容易に格納できます。
関連項目: Javaの巨大ノードに関する機能の詳細は、『Oracle XML DB Developer's Guide』を参照してください。 |
XMLParser
は、XML Parser for Javaの抽象ベース・クラスです。インスタンス化されたパーサーは、parse()
メソッドを起動してXML文書を読み取ります。
XMLDOMImplementation
ファクトリ・メソッドは、別のメソッドを提供してバイナリXMLを解析し、拡張性のあるDOMを作成します。
図4-1に、XMLParser
を使用した解析の基本プロセスを示します。この図はXMLDOMImplementation
()には適用されません。
Javaアプリケーションでは、次のAPIを使用して、解析済XML文書にアクセスできます。
DOM APIは、XML文書を解析し、メモリー内に文書のツリー表現を構築します。DOMParser
オブジェクトを使用してDOM解析をするか、XMLDOMImplementation
インタフェース・ファクトリ・メソッドを使用してプラグ可能な拡張性のあるDOMを作成するかのいずれかをします。
SAX APIは、XML文書をイベントのストリームとして処理します。したがって、プログラムから文書内のランダムな位置へのアクセスはできません。SAXを使用した解析にはSAXParser
オブジェクトを使用します。
JAXPは、DOM、SAXおよびXSLをサポートするJava固有のAPIです。JAXPを使用した解析にはDocumentBuilder
またはSAXParser
オブジェクトを使用します。
例4-1に、DOM、SAX、JAXPの違いを明示するサンプルXML文書を示します。
DOMは、メモリー内にXML文書のツリー表現を構築します。たとえば、DOM APIでは例4-1に示した文書を受け取り、図4-2に示すメモリー内ツリーを作成します。DOMは、ツリーをナビゲートおよび処理するためのクラスおよびメソッドを提供します。
一般的に、DOM APIには次の利点があります。
オブジェクトのツリー構造が提供されるため、DOM APIはSAXよりも簡単に使用できます。
要素の並替え、要素や属性の追加と削除、要素名の変更など、XMLツリーの構造的な操作を実行できます。
対話型アプリケーションでメモリー内にオブジェクト・モデルを格納できるため、ユーザーがオブジェクト・モデルにアクセスして操作できます。
標準としてのDOMはXPathをサポートしません。ただし、ほとんどのXPath実装ではDOMが使用されています。Oracle XDKには、XPathをサポートするためのDOM API拡張が含まれています。
プラグ可能な拡張性のあるDOMは、スケーラビリティと能率性を大幅に改善するように作成されます。
Oracle 11gリリース1(11.1)では、XDKはプラグ可能な拡張性のあるDOMをサポートしています。これにより、メモリーの非効率、限定的なスケーラビリティ、DOM構成の制御不足という問題が緩和されます。
拡張性のあるDOMに関しては、構成および作成は主にXMLDOMImplementation
クラスを使用してサポートされます。
これらは拡張性のあるDOMの重要な側面です。
プラグイン・データにより、外部XML表現は内部表現の複製XMLを使用せずに、直接、拡張性のあるDOMによって使用が可能になります。
拡張性のあるDOMは、Reader
およびInfosetWriter
抽象インタフェースを介してプラグインXMLデータの上位で作成されます。XMLデータは、バイナリXML、XMLType
およびサード・パーティ製のDOMなどとは形式が異なる可能性もあります。
一時ノード。DOMノードは容易に作成でき、使用中でない場合は解放できます。
バイナリXML
拡張性のあるDOMは、入力および出力形式ともにバイナリXMLを使用できます。拡張性のあるDOMは、次の2つの方法でデータと対話します。
抽象InfosetReader
およびInfosetWriter
インタフェースを介して対話。ユーザーは、(1)InfosetReader
およびInfosetWriter
のBinXML
実装を使用して、BinXML
データの読取りおよび書込みを実行でき、(2)ユーザーが提供する他の実装を使用して、XML Information Setの他の形式に読取りおよび書込みを実行できます。
BinXMLStream
に対するInfosetReader
およびInfosetWriter
アダプタの実装を介して対話。
拡張性のあるDOMのサポートは次のもので構成されています。
プラグ可能なDOMは、データ・レイヤーからDOM APIを分割可能にするXDKメカニズムです。DOM APIは、InfosetReader
およびInfosetWriter
インタフェースによってデータから分離されます。
プラグ可能なDOMを使用すると、1つのプロセッサから別のプロセッサへのXMLデータの移動が容易になります。
DOM APIには、データの上位に統合された標準APIが含まれており、ノード・アクセス、ナビゲーション、更新プロセスおよび検索機能がサポートされています。
遅延マテリアライズ・メカニズムを使用すると、XDKはアクセスするノードのみを作成し、使用しないノードをメモリーから解放します。スケーラビリティが向上するため、非常に大きなXML文書も処理可能です。
DOM構成は他のアプリケーションに適合するように構成されています。DOMの構成には、読取り専用、ストリーム、一時更新およびシャドウ・コピーなど様々なアクセス・パターンを使用して、最大限のメモリーを使用および実行可能にできます。
DOMとは異なりSAXはイベントベースであるため、入力文書のメモリー内ツリー表現を構築しません。SAXは、要素単位で入力文書を処理し、イベントと重要なデータをアプリケーションのコールバック・メソッドに報告できます。例4-1に示すXML文書は、図4-2に示す一連の線形イベントとして解析されます。
一般的に、SAX APIには次の利点があります。
XMLツリーの操作が必要でない検索操作やその他のプログラムに有用です。
メモリー・リソースを大量に消費しません。
データベースからXML文書を取得する場合はDOMよりも高速です。
JAXP APIを使用すると、SAXまたはDOMパーサーの実装をプラグインできます。Oracle XDKで提供されているSAX APIとDOM APIは、JAXPがサポートするベンダー固有実装の例です。
一般的にJAXPの利点は、相互運用可能なアプリケーションを作成できることです。アプリケーションでは、JAXPを介して使用可能な機能を使用する場合、非常に簡単に実装を切り替えることができます。
JAXPの主な短所は、ベンダー固有のAPIよりも実行速度が遅いことです。また、JAXP APIでは使用できず、Oracle固有のAPIを介して使用できる機能もあります。Oracle固有の機能は、その一部のみが、JAXPに用意されている拡張メカニズムを介して使用できます。ただし、アプリケーションでこれらの拡張を使用する場合は、実装を柔軟に切り替えることはできません。
XML Parser for Javaは、非修飾の要素タイプおよび属性名と、名前空間内の要素タイプおよび属性名を解析できます。名前空間は、汎用の名前を提供することにより、XML文書内にある要素タイプ間または属性間の名前の競合を解決または回避するメカニズムです。例4-2に示すXML文書について考えてみます。
例4-2 名前空間を使用しないサンプルXML文書
<?xml version='1.0'?> <addresslist> <company> <address>500 Oracle Parkway, Redwood Shores, CA 94065 </address> </company> <!-- ... --> <employee> <lastname>King</lastname> <address>3290 W Big Beaver Troy, MI 48084 </address> </employee> <!-- ... --> </addresslist>
名前空間を使用しない場合、例4-2のXML文書を処理するアプリケーションでは、<address>
タグが会社の住所と従業員の住所のどちらを参照しているかを判断できません。例4-3に示すように、名前空間を使用して<address>
タグを区別できます。例では、次のXML名前空間を宣言します。
http://www.oracle.com/employee http://www.oracle.com/company
例4-3では、com
接頭辞を最初の名前空間に関連付け、emp
接頭辞を2番目の名前空間に関連付けています。したがって、アプリケーションは<com:address>
と<emp:address>
を区別できます。
例4-3 名前空間を使用したサンプルXML文書
<?xml version='1.0'?> <addresslist> <!-- ... --> <com:company xmlns:com="http://www.oracle.com/company"> <com:address>500 Oracle Parkway, Redwood Shores, CA 94065 </com:address> </com:company> <!-- ... --> <emp:employee xmlns:emp="http://www.oracle.com/employee"> <emp:lastname>King</emp:lastname> <emp:address>3290 W Big Beaver Troy, MI 48084 </emp:address> </emp:employee>
名前空間を使用する文書を解析する際に、次の用語を覚えておくと役に立ちます。
名前空間の接頭辞は、xmlns
で宣言された名前空間接頭辞です。例4-3では、emp
およびcom
が名前空間の接頭辞です。
ローカル名は、名前空間の接頭辞が付いていない要素または属性の名前です。例4-3では、employee
およびcompany
がローカル名です。
修飾名は、ローカル名に接頭辞を加えたものです。例4-3では、emp:employee
およびcom:company
が修飾名です。
名前空間URIは、xmlns
に割り当てられているURIです。例4-3では、http://www.oracle.com/employee
およびhttp://www.oracle.com/company
が名前空間URIです。
拡張名は、名前空間の接頭辞を名前空間URIで置換することで取得されます。例4-3では、http://www.oracle.com/employee:employee
およびhttp://www.oracle.com/company:company
が拡張要素名です。
アプリケーションは、parse()
メソッドを起動してXML文書を解析します。通常、アプリケーションはparse()
メソッドに関連して初期化メソッドおよび終了メソッドを起動します。oracle.xml.parser.v2.XMLParser
に定義されているsetValidationMode()
メソッドを使用して、パーサーのモードを検証または非検証に設定できます。
検証モードのXMLパーサー(検証XMLパーサー)は、DTDまたはXMLスキーマで指定されたルールに従ってXML文書を解析し、文書が指定したDTDまたはXMLスキーマに準拠しているかどうかを判断します。XML文書が準拠しない場合は文書が有効であり、文書の構造はDTDまたはスキーマのルールに準拠しています。非検証モードのパーサー(非検証パーサー)では、整形式であるかどうかのみが確認されます。
表4-1に、Oracle XDK Parserの検証モードを設定するためにsetValidationMode()
で使用できるフラグを示します。
表4-1 XML Parser for Javaの検証モード
名前 | 値 | XML Parserによる処理 |
---|---|---|
非検証モード |
|
XMLが整形式であることを確認し、データを解析します。 |
|
XMLが整形式であることを確認し、XMLデータがDTDに対して妥当であるかどうかを検証します。 |
|
|
XML文書を、その文書に対して指定されたXMLスキーマに従って検証します。 |
|
LAX検証モード |
|
スキーマ定義が検出されなくなるまで、インスタンス・ドキュメントの一部またはすべての検証を試行します。定義が検出されない場合も、エラーは発生しません。 |
厳密な検証モード |
|
インスタンス・ドキュメント全体の検証を試行します。スキーマ定義が検出されない場合またはインスタンスが定義に準拠しない場合は、エラーが発生します。 |
|
DTD(存在する場合)に従って、入力XML文書のすべてまたは一部を検証します。DTDが存在しない場合、パーサーは非検証モードに設定されます。 |
|
|
DTDまたはXMLスキーマ(存在する場合)に従って、入力XML文書のすべてまたは一部を検証します。DTDとXMLスキーマのいずれも存在しない場合、パーサーは非検証モードに設定されます。 |
setValidationMode()
での検証モードの設定に加えて、oracle.xml.parser.schema.XSDBuilder
クラスを使用してXMLスキーマを構築し、XMLParser.setXMLSchema()
メソッドを起動することにより、このXMLスキーマを使用するようにパーサーを構成できます。この場合、XMLパーサーは検証モードを自動的にSCHEMA_STRICT_VALIDATION
に設定し、schemaLocation
およびnoNamespaceSchemaLocation
属性を無視します。検証モードをSCHEMA_LAX_VALIDATION
に変更することもできます。XMLParser.setDoctype()
メソッドは、DTDのパラレル・メソッドですが、setXMLSchema()
とは異なり、検証モードを変更しません。
関連項目:
|
XML Parserに実装されているXML Compressorを使用して、XML文書を圧縮および解凍できます。圧縮アルゴリズムは、XMLタグのトークン化に基づいています。これは、すべてのXML文書にはタグの繰返しがあるため、それらのタグをトークン化すると、データが大幅に圧縮されることを前提としています。圧縮の程度は、文書のタイプに依存します。タグの数が多く、テキスト・コンテンツが少ないほど、圧縮率が向上します。
Oracle XML Parserは、メモリー内のDOMツリー、またはXML文書から生成されたSAXイベントから、圧縮したバイナリ出力を生成します。表4-2に、2種類の圧縮を示します。
表4-2 DOMとSAXでのXML圧縮
タイプ | 説明 | 圧縮API |
---|---|---|
DOMベース |
目的は、DOMツリーの構造情報および階層情報を失うことなく、XML文書のサイズを小さくすることです。パーサーでは、解析済XML文書に対応するメモリー内DOMツリーがシリアライズされ、圧縮したXML出力ストリームが生成されます。シリアライズされたストリームは、再度読み取られると、DOMツリーを再生成します。 |
|
SAXベース |
SAXパーサーでは、XMLファイルを解析する際に圧縮したストリームが生成されます。SAXパーサーによって生成されたSAXイベントは、SAX圧縮ユーティリティによって処理されます。SAX圧縮ユーティリティは、圧縮したバイナリ・ストリームを生成します。バイナリ・ストリームが再度読み取られると、SAXイベントが生成されます。 |
圧縮したXMLを生成するには、出力ストリームをコンストラクタに渡すことにより、 注意: |
DOMおよびSAXから生成された圧縮ストリームには互換性があるため、SAXから生成された圧縮ストリームを使用してDOMツリーを生成したり、DOMから生成された圧縮ストリームを使用してSAXイベントを生成したりできます。通常、XML文書と同様に、圧縮したXMLデータ出力はデータベースにBLOB
として格納できます。
プログラムで大きなXML文書を解析し、メモリー内にDOMツリーを作成すると、パフォーマンスに影響する場合があります。DOMツリーをシリアライズすることにより、XML文書をバイナリ・ストリームに圧縮できます。圧縮したストリーム内のXMLデータを検証せずに、DOMツリーを再生成できます。圧縮したストリームはシリアライズされたストリームとして処理できますが、ストリーム内のデータは、Javaのデフォルトのシリアライズによって実装される圧縮よりも厳密に制御および管理されます。
注意: Oracle Textは、圧縮されたXML文書を検索できません。解凍によりパフォーマンスが低下します。クライアントとサーバー間でファイルを転送している場合は、HTTP圧縮の方が簡単です。 |
XML開発の基本コンポーネントはXML Parsingです。XML Parsing for JavaはスタンドアロンのXMLコンポーネントであり、プログラムで処理できるように、XML文書(あるいはスタンドアロンのDTDまたはXMLスキーマ)を解析します。この項の内容は次のとおりです。
図4-3に、標準的なXML処理アプリケーションでXMLパーサーを使用する方法を示します。
図4-3に示したアプリケーションの基本プロセスは次のとおりです。
DOMまたはSAXパーサーにより、入力XML文書が解析されます。たとえば、プログラムはXMLデータ文書、DTD、XMLスキーマおよびXSLスタイルシートを解析できます。
検証パーサーを実装すると、プロセッサは、提供されているDTDまたはXMLスキーマに対してXMLデータ文書が妥当であるかどうかの検証を試行します。
関連項目:
|
XML Parser for Javaのデモ・プログラムは、$ORACLE_HOME/xdk/demo/java/parser
にあります。表4-3に、デモ・プログラムが格納されているサブディレクトリを示します。
表4-3 Javaパーサーのデモ
ディレクトリ | 内容 | プログラムの説明 |
---|---|---|
|
class.xml DemoUtil.java empl.xml family.dtd family.xml iden.xsl NSExample.xml traversal.xml |
XMLパーサーで一般的に使用するXMLファイルおよびJavaプログラムです。たとえば、XSLTスタイルシート |
|
DOMCompression.java DOMDeCompression.java SAXCompression.java SAXDeCompression.java SampleSAXHandler.java sample.xml xml.ser |
DOMおよびSAX圧縮を示します。
|
|
AutoDetectEncoding.java DOM2Namespace.java DOMNamespace.java DOMRangeSample.java DOMSample.java EventSample.java I18nSafeXMLFileWritingSample.java NodeIteratorSample.java ParseXMLFromString.java TreeWalkerSample.java |
DOM APIの使用方法を示します。
|
|
JAXPExamples.java age.xsl general.xml jaxpone.xml jaxpone.xsl jaxpthree.xsl jaxptwo.xsl oraContentHandler.java |
JAXP APIの様々な使用方法を示します。
|
|
SAX2Namespace.java SAXNamespace.java SAXSample.java Tokenizer.java |
SAX APIの様々な使用方法を示します。
|
|
XSLSample.java XSLSample2.java match.xml match.xsl math.xml math.xsl number.xml number.xsl position.xml position.xsl reverse.xml reverse.xsl string.xml string.xsl style.txt variable.xml variable.xsl |
XSLTを使用した文書の変換を示します。
関連項目: 「XSLTプロセッサのデモ・プログラムの実行」 |
サンプル・プログラムのコンパイルおよび実行方法に関するドキュメントは、READMEにあります。基本手順は次のとおりです。
ディレクトリを$ORACLE_HOME/xdk/demo/java/parser
ディレクトリ(UNIXの場合)または%ORACLE_HOME%\xdk\demo\java\parser
ディレクトリ(Windowsの場合)に変更します。
「Java XDK環境の設定」の説明に従って、環境を設定します。
次の各サブディレクトリに変更し、コマンドラインでmake
(UNIXの場合)またはMake.bat
(Windowsの場合)を実行します。次に例を示します。
cd comp;make;cd .. cd jaxp;make;cd .. cd sax;make;cd .. cd dom;make;cd .. cd xslt;make;cd ..
makeファイルでは、各ディレクトリ内のソース・コードがコンパイルされ、プログラムが実行され、各プログラムの出力が*.out
という拡張子の付いたファイルに書き込まれます。
*.out
ファイルを表示して、プログラムの出力を参照できます。
$ORACLE_HOME/bin
(UNIXの場合)または%ORACLE_HOME%\bin
(Windowsの場合)にあるoraxml
ユーティリティは、XML文書を解析するコマンドライン・インタフェースです。XML文書が整形式であるか、および妥当であるかを確認します。
oraxml
を使用するには、次の条件に該当することを確認する必要があります。
「Java XDK環境の設定」の説明に従ってCLASSPATH
が設定されていること。特に、環境変数CLASSPATH
がxmlparserv2.jar
ファイルを指していることを確認してください。
環境変数PATH
が、使用しているJDKのバージョンに付属するJavaインタプリタを検索できること。
表4-4に、oraxml
のコマンドライン・オプションを示します。
オプション | 用途 |
---|---|
- |
ヘルプ・メッセージを出力します。 |
- |
バージョン番号の出力 |
- |
入力ファイルが整形式かどうかの確認 |
- |
DTD検証を使用した入力ファイルの検証 |
- |
スキーマ検証を使用した入力ファイルの検証 |
- |
出力ログ・ファイルへのエラーの書込み |
- |
入力XMLファイルの圧縮 |
- |
入力圧縮ファイルの解凍 |
- |
入力ファイルのエンコーディングの出力 |
- |
警告の表示 |
たとえば、$ORACLE_HOME/xdk/demo/java/parser/common
ディレクトリに変更します。コマンドラインで次のコマンドを実行することにより、文書family.xml
がfamily.dtd
に対して妥当であるかどうかを検証できます。
oraxml -dtd -enc family.xml
出力は次のようになります。
The encoding of the input file: UTF-8The input XML file is parsed without errors using DTD validation mode.
W3C標準ライブラリorg.w3c.dom
では、Document
クラスと、DOMのコンポーネント用のクラスが定義されています。Oracle XML Parserには、標準のDOM APIが組み込まれており、W3C DOMの勧告に準拠しています。org.w3c.dom
とともに、Oracle XML Parsingには、DOM APIを実装するクラスが組み込まれており、これらを拡張して文書フラグメントの出力や名前空間情報の取得などの機能を提供しています。
この項の内容は次のとおりです。
XMLアプリケーションにDOMベースのコンポーネントを実装するには、次のXDKクラスを使用します。
oracle.xml.parser.v2.DOMParser
。このクラスは、W3C勧告に準拠したXML 1.0のパーサーを実装します。DOMParser
はXMLParser
を拡張するため、XMLParser
のすべてのメソッドはDOMParser
で使用できます。
oracle.xml.parser.v2.XMLDOMImplementation
。このクラスにはプラグ可能な拡張性のあるDOMを作成するファクトリ・メソッドが含まれます。
つまり、XMLDOMImplementation
クラスで作成されたDOMがプラグ可能な拡張性のあるDOMです。
DOMNamespace
およびDOM2Namespace
クラスも利用できます。これらのクラスは、$ORACLE_HOME/xdk/demo/java/parser/dom
に含まれているサンプル・プログラムです。
例4-4に、DOMパーサーのアーキテクチャを示します。
プログラムDOMSample.java
に、入力XML文書の解析およびDOMを介してのアクセスへの基本手順の説明があります。
プログラムは、入力としてXMLファイルを受け取って解析し、DOMツリー内の要素と属性を出力します。
これらの手順により、使用可能なメソッドおよびインタフェースを提供する表への参照できます。
DOMParser()
コンストラクタをコールすることにより、DOMParser
オブジェクトを作成します。このパーサーを使用して、入力XMLデータ文書とDTDを解析できます。DOMSample.java
の次のコード部分は、この方法を示します。
DOMParser parser = new DOMParser();
パーサーのプロパティを構成します。表4-5を参照してください。
DOMSample.java
の次のコード部分は、エラー出力ストリームを指定し、検証モードをDTD検証に設定して、警告メッセージを有効にします。
parser.setErrorStream(System.err); parser.setValidationMode(DOMParser.DTD_VALIDATION); parser.showWarnings(true);
parse()
メソッドを起動することにより、入力XML文書を解析します。このプログラムでは、Node
オブジェクトのツリーをメモリーに構築します。
DOMSample.java
のこのコード部分は、java.net.URL
クラスのインスタンスを解析する方法を示します。
parser.parse(url);
XML入力は、ファイル、文字列バッファまたはURLのいずれかになることに注意してください。次のコード部分に示すとおり、DOMSample.java
はファイル名をパラメータとして受け入れ、createURL
ヘルパー・メソッドをコールして、パーサーに渡すことのできるURLオブジェクトを作成します。
public class DOMSample { static public void main(String[] argv) { try { if (argv.length != 1) { // Must pass in the name of the XML file. System.err.println("Usage: java DOMSample filename"); System.exit(1); } ... // Generate a URL from the filename. URL url = DemoUtil.createURL(argv[0]); ...
getDocument()
を起動して、パーサーがメモリー内DOMツリーのルートへのハンドルを取得します。このハンドルはXMLDocument
オブジェクトです。このハンドルを使用して、解析されたXML文書のすべての部分にアクセスできます。表4-6に、XMLDocument
クラスが実装するインタフェースを示します。
DOMSample.java
のこのコード部分は、この方法を示します。
XMLDocument doc = parser.getDocument();
様々なXMLDocument
メソッドをコールすることにより、取得した文書のDOMノードを取得および操作します。表4-7を参照してください。
DOMSample.java
の次のコード部分は、DOMParser.print()
メソッドを使用して、DOMツリーの要素および属性を出力します。
System.out.print("The elements are: "); printElements(doc); System.out.println("The attributes of each element are: "); printElementAttributes(doc);
プログラムは、printElements()
メソッドを実装します。このメソッドは、getElementsByTagName()
をコールして、DOMツリー内のすべての要素のリストを取得します。次に、リスト内の各アイテムをループし、getNodeName()
をコールして各要素の名前を出力します。
static void printElements(Document doc) { NodeList nl = doc.getElementsByTagName("*"); Node n; for (int i=0; i<nl.getLength(); i++) { n = nl.item(i); System.out.print(n.getNodeName() + " "); } System.out.println(); }
プログラムは、printElementAttributes()
メソッドを実装します。このメソッドは、Document.getElementsByTagName()
をコールして、DOMツリー内のすべての要素のリストを取得します。次に、リスト内の各要素をループし、Element.getAttributes()
をコールして要素の属性のリストを取得します。次に、Node.getNodeName()
をコールして属性名を取得し、Node.getNodeValue()
をコールして属性値を取得します。
static void printElementAttributes(Document doc) { NodeList nl = doc.getElementsByTagName("*"); Element e; Node n; NamedNodeMap nnm; String attrname; String attrval; int i, len; len = nl.getLength(); for (int j=0; j < len; j++) { e = (Element)nl.item(j); System.out.println(e.getTagName() + ":"); nnm = e.getAttributes(); if (nnm != null) { for (i=0; i<nnm.getLength(); i++) { n = nnm.item(i); attrname = n.getNodeName(); attrval = n.getNodeValue(); System.out.print(" " + attrname + " = " + attrval); } } System.out.println(); } }
reset()
メソッドを起動することにより、パーサーの状態をリセットします。これで、パーサーが新規文書を解析する準備ができます。
次の表に、「基本的なDOM解析の実行」で作成したようなアプリケーションの作成に使用する有用なメソッドおよびインタフェースを示します。
表4-5に、有用な構成メソッドを示します。
表4-5 DOMParser構成メソッド
メソッド | メソッドの用途 |
---|---|
|
外部エンティティとDTDをロードするためのベースURLを設定します。このメソッドは、XML文書が |
|
解析時に使用するDTDを指定します。 |
|
エラーと警告の出力の出力ストリームを作成します。 |
|
入力XML文書に空白を保持するようにパーサーに指示します。 |
|
パーサーの検証モードを設定します。表4-1に、このメソッドで使用できるフラグを示します。 |
|
パーサーが警告を出力する必要があるかどうかを指定します。 |
表4-6に、XMLDocument
クラスが実装するインタフェースを示します。
表4-6 XMLDocumentにより実装されるいくつかのインタフェース
インタフェース | 定義内容 |
---|---|
|
文書ツリー内の単一ノードと、ノードをアクセスおよび処理するためのメソッド |
|
XML文書全体を表す |
|
XML要素を表す |
表4-7に、ノードを取得するときに役立つメソッドをいくつか示します。
表4-7 有用なXMLDocumentのメソッド
メソッド | メソッドの用途 |
---|---|
|
このノードが要素である場合はその属性を含む |
|
特定のレベルの特定のタグ名と一致するすべての要素を再帰的に取得します。このメソッドでは、任意のタグと一致する |
|
要素の拡張名を取得します。このメソッドは、 |
|
この要素のローカル名を取得します。要素名が |
|
このノードの名前空間URIを取得するか、名前空間URIが指定されていない場合は |
|
DOMツリー内のノードの名前を取得します。 |
|
タイプに応じて、このノードの値を取得します。このモードは、 |
|
要素の名前空間の接頭辞を取得します。 |
|
要素の修飾名を取得します。要素名が |
|
DOMツリー内の要素の名前を取得します。 |
この項では、拡張性のあるDOMの作成および使用方法について説明します。
この項の内容は次のとおりです。
プラグ可能なDOMはデータからDOM APIを分割します。基礎となるデータは、内部またはプラグインのいずれかで、いずれの場合もバイナリXMLです。
内部データ
XMLテキストが解析されていない内部データをプラグインするには、XMLテキストはバイナリXMLとして保存され、DOMParser
によって解析される必要があります。解析済バイナリXMLは、DOM APIレイヤーのInfoSetReader
にプラグインされます。
InfosetReader
引数は、基礎となるXMLデータへのインタフェースです。
プラグイン・データ
プラグイン・データはすでに解析済のデータなので、プロセッサ間の転送で解析は不要です。
プラグ可能なDOMを作成するには、XMLデータは、たとえばXMLDOMImplementation
オブジェクト上のInfosetReader
インタフェースを介してプラグインされます。
public Document createDocument(InfosetReader reader) throws DOMException
InfosetReader
APIはXDKBinXMLStream
の上位に実装されます。DOM4J、JDOMまたはJDBCなどのXMLデータの他の形式のオプションのアダプタも、サポートされます。ユーザーは独自の実装にもプラグインできます。
InfosetReader
は、拡張性のあるDOM APIレイヤーおよび基礎となるデータ間のインタフェースとして機能します。XMLデータにアクセスするのは、一般的なストリームベースのPull APIです。InfosetReader
は、XMLストリームからシーケンシャルなイベントを取得し、これらのイベントから状態およびデータの問合せを実行します。次の例では、XMLデータがスキャンされ、QName
およびすべての要素の属性が取得されています。
InfosetReader reader; While (reader.hasNext()) { reader.next(); if (reader.getEventType() == START_ELEMENT) { QName name = reader.getQName(); TypedAttributeList attrList = reader.getAttributeList(); } }
InfosetReader
インタフェースは次の機能をサポートしています。
コピー: 文書間のDOMのシャドウ・コピーをサポートするには、InfosetReader
の新規コピーを作成して、Clone
メソッドを使用して、スレッドを安全にします。BinXMLStream
から取得されたInfosetReader
は、常にこれをサポートします(オプション)。
フォーカスの移動: 遅延マテリアライズをサポートするには、InfosetReader
は、Offset
によって指定されたどの場所にもフォーカスを移動できます(オプション)。
If (reader.hasSeekSupport())
reader.seek(offset);
InfosetWriter
は、データ書込みをサポートするInfosetReader
インタフェースの拡張機能です。XDKでは、バイナリXMLの上位で実装されます。ユーザーはこの実装を変更できません。
XMLテキストから拡張性のあるDOMを作成するには、DOMParser
実行前に、XMLテキストをバイナリXMLとして保存する必要があります。次のいずれかでもXMLテキストを保存できます。
バイナリXML
バイナリXMLへの参照: データ・ソースがデシリアライズに使用可能と判明している場合は、現在のデータのかわりにバイナリXMLの参照項目を保存できます。
次の例に、バイナリXMLとしての保存方法を示します。
XMLDocument doc;
InfosetWriter writer;
doc.save(writer, false);
writer.close();
バイナリXMLへの参照として保存するには、save
コマンドに対する引数としてtrue
を使用します。
遅延マテリアライズを使用して、空のDOMをプラグインできます。それにより、必要な場合はより多くのデータを取り出せ、不要になったらノードを解放できます。
プラグインDOMアーキテクチャは、ツリーのルートとして単一のDocument
ノードを含む空のDOMを作成します。残りのDOMツリーは、後でアクセスして拡張できます。ノードには拡張されない子や兄弟関係のノードがある場合もありますが、親および祖先は常に拡張されます。DOMはデータを取り出して次のノードを作成できるように、各ノードは次のノードのInfoSetReader.Offset
プロパティを保持します。
アクセス・メソッド・タイプによっては、DOMノードは戻されたノードのセット以上に拡張する場合もあります。
DOMナビゲーション
DOMナビゲーション・インタフェースは、最初の子や、最後の子、親、兄弟関係などの近隣のノードへのアクセスを可能にします。ノード作成が必要な場合は、ドキュメント内の順に行われます。
IDの索引付け
DTDまたはXMLスキーマは、型IDでノードを指定できます。DOMがIDの索引付けをサポートする場合、それらのノードは、索引を使用して直接取出し可能になります。拡張性のあるDOMの場合、索引による取得で、前のすべてのノードが拡張されるわけではありませんが、祖先のノードは生成されます。
Xpath式
XPath評価により、メモリー内のすべての中間ノードが生成されます。たとえば、子孫の軸「//」により全体のサブツリーが拡張されますが、評価後に解放されるものもあります。
拡張性のあるDOMは、ノードの手動参照解除または自動参照解除のいずれかをサポートします。
弱参照を使用した自動参照解除
自動参照解除を有効化するには、PARTIAL_DOM
属性をBoolean.TRUE
に設定します。
DOMナビゲーションをサポートしている場合は、ノード間のクロス参照を追加する必要があります。自動参照解除モードでは、リンクのいくつかは弱参照で、不要データ収集時に解放されます。
リンクの重要性に基づいてノードが解放されます。親ノードへのリンクは削除されません。有効範囲内の名前空間に祖先がコンテキストを提供し、InfosetReader
などのストリームAPIを使用して削除済の親ノードを取得するのは難しいためです。
拡張性のあるDOMは、親および兄弟関係を強く保持しますが、子や次のような兄弟関係の保持は弱いです。Java仮想マシンがノードを解放されても、それらへの参照は基礎となるデータで使用可能であるため、必要な場合は再作成できます。
手動参照解除
手動参照解除を有効化するには、属性PARTIAL_DOM
をBoolean.FALSE
に設定して、プラグインXMLデータを使用してDOMを作成します。
このモードでは、DOMはアプリケーションに依存し、ツリー全体からドキュメント・フラグメントを明示的に参照解除します。弱参照はありません。アプリケーションに決定的なデータ処理の順序がある場合、ノードの解放と再作成の繰り返し行う余分なオーバーヘッドは回避することをお薦めします。
すべての他のノードから参照解除を実行するには、freeNode()
をコールします。次に例を示します。
Element root = doc.getDocumentElement();
Node item = root.getFirstChild();
While (item != null)
{
processItem(item);
Node tmp = item;
item = item.getNextSibling();
((XMLNode)tmp).freeNode();
}
拡張性のないDOMではfreeNode
コールは適用されません。
参照解除するノードはDOMツリーから削除されたノードとは異なることに注意してください。DOMツリーは、freeNode
がDOMノード上でコールされても変更しません。ノードは、その親や兄弟関係からアクセスおよび再作成可能です。ただし、ノード解放後にノードにアクセスする場合は、ノードを保持する変数によってエラーがスローされます。
シャドウ・コピーを使用して、下部のデータはデータ複製を避けるために共有できます。
XML処理の共通操作であるクローン作成は、プラグ可能なDOMで簡単に実行できます。
copy
メソッドが使用されると、コピーされたフラグメントのルート・ノードが作成され、サブツリーはオンデマンドで拡張されます。
データ共有は基礎となるデータに対するもので、DOMノード自体に対してではありません。DOM仕様では、クローンとそのオリジナルではノード識別および親ノードを別のものにする必要があります。
DOM APIは、追加、削除ノード、設定、削除、変更および挿入値などの更新操作をサポートします。DOMがプラグインXMLデータで作成されると、基礎となるデータはDOMの外部とみなされます。DOM更新は、DOM APIから表示可能ですがデータ・ソースは同一のままです。通常の更新操作は使用可能ですが、相互に妨害はしません。
変更済のDOMを永続にするには、DOMを明示的に保存する必要があります。これによりすべての変更はオリジナル・データとともにマージされ、永続格納にデータがシリアライズされます。変更したDOMを明示的に保存しない場合は、トランザクションを終了すると変更が失われます。
XMLテキストは、DOMParser
で解析および構成されて拡張性のあるDOMが作成されると、内部データはバイナリXMLの形式でキャッシュされ、DOM APIレイヤーは内部データの上位で構築されます。バイナリXMLはDOMノードよりさらにコンパクトであるため、これによりスケーラビリティが増大されます。
追加のスケーラビリティに関しては、拡張性のあるDOMはPageManager
インタフェースを介してバイナリ・データのバックエンド格納を使用できます。バイナリ・データは、使用していないメモリーと交換可能です。
このコードの例に、PageManager
インタフェースの使用方法を示します。
DOMParser parser = new DOMParser(); parser.setAttribute(PARTIAL_DOM, Boolean.TRUE); //enable scalable DOM parser.setAttribute(PAGE_MANAGER, new FilePageManager("pageFile")); ... // DOMParser other configuration parser.parse(fileURL); XMLDocument doc = parser.getDocument();
PageManager
インタフェースが使用されていない場合、パーサーはバイナリXMLとして文書全体をキャッシュします。
XMLDOMImplementation
クラスを使用してDOMを作成する場合、XMLDOMImplementation
クラスのsetAttribute
メソッドを使用して、DOMを構成して異なるアプリケーションに適合でき、効率を最大にできます。
public void setAttribute(String name, Object value) throws IllegalArgumentException
拡張性のあるDOMに関しては、PARTIAL_DOM
およびACCESS_MODE
属性に対してsetAttribute
をコールします。
注意: 新規の属性値が影響するのは次のDOMであり、現在のものではありません。そのため、XMLDOMImplementation のインスタンスは、別の構成でDOMを作成するのに使用されます。 |
PARTIAL_DOM
この属性は、DOMに拡張性があるかどうか(部分的)、ブール値を取るかどうかを示します。DOM作成は、属性がTRUE
に設定されている場合は拡張性があります。必要な場合は、使用されていないノードが解放され、再作成されます。属性がFALSE
に設定されている、または設定がない場合はDOM作成に拡張性はありません。
ACCESS_MODE
この属性は、DOMのアクセスを制御し、拡張性のあるDOMおよび拡張性のないDOMの両方に適用します。次の値があります。
UPDATEABLE
DOMはすべてのDOM更新操作をサポートします。
UPDATEABLE
はACCESS_MODE
属性のデフォルト値で、XDK DOM実装との下位互換性を保持します。
READ_ONLY
DOMはこの読取りのみできます。
DOMツリーを変更しようとするとエラーが出ますが、新規ノードがDOMツリーに追加されないかぎりクローン作成などのノード作成は可能です。
FORWARD_READ
この値は、getFirstChild()
.getNextSibling()
やgetLastChild()
などのナビゲーションを有効にしますが、getPreviousSibling()
などの下位アクセスはできません。
FORWARD_READ
は親ノードや祖先ノードにアクセス可能です。
STREAMING
DOMアクセスは、SAXイベント・アクセスに類似したドキュメント内の順での、ノードのストリームに限定されます。
ストリーム・モードでの現在のノードの概念に従って、現在のノードは、ドキュメント内の順にアクセスした最後のノードです。アプリケーションは変数内にノードを保持し、再度アクセスしますが、DOMメソッドを使用して現在のノードの前に他のノードにアクセスすると、DOMエラーを引き起こします。ただし、祖先のノードおよび属性ノードへのアクセスは常に可能です。
次に、ストリーム・モードでのDOMの動作を示します。
Node parent = currentNode.getParentNode(); // OK although parent is before current node
Node child = parent.getFirstChild(); // Error if the current node is not the first child of parent!
Attribute attr = parent.getFirstAttribute();// OK accessing attributes from Element is always //allowed
次に、アクセス・モードを制限の低いものから高いものの順に示します。
UPDATEABLE
> READ_ONLY
> FORWARD_READ
> STREAM_READ
DOMはREAD_ONLY
モードで変更できません。そのため書込みバッファ全体は必要ありません。
DOMはFORWARD_READ
モードで祖先のノード以外の下位を読み取りません。したがって、兄弟関係のリンクは作成されません。
DOMは親リンクのみ保持し、STREAM_READ
モードでノードのデータの場所を記憶する必要はありません。したがって、解放されたノードは再作成される必要はありません。
ここでは、プラグ可能な拡張性のあるDOMを作成および使用するアプリケーションを示します。
XMLDOMImplementation domimpl = new XMLDOMImplementation(); domimpl.setAttribute(XMLDocument.SCALABLE_DOM, Boolean.TRUE); domimpl.setAttribute(XMLDocument.ACCESS_MODE,XMLDocument.UPDATEABLE); XMLDocument scalableDoc = (XMLDocument) domimpl.createDocument(reader);
プラグ可能で、拡張性のある、バイナリXMLに基づくDOMを作成および使用するアプリケーションを次に示します。詳細は第5章「バイナリXML for Javaの使用」を参照してください。
BinXMLProcessor proc = BinXMLProcessorFactory.createProcessor(); BinXMLStream bstr = proc.createBinXMLStream(); BinXMLEncoder enc = bstr.getEncoder(); enc.setProperty(BinXMLEncoder.ENC_SCHEMA_AWARE, false); SAXParser parser = new SAXParser(); parser.setContentHandler(enc.getContentHandler()); parser.setErrorHandler(enc.getErrorHandler()); parser.parse(BinXMLUtil.createURL(xmlfile)); BinXMLDecoder dec = bstr.getDecoder(); InfosetReader reader = dec.getReader(); XMLDOMImplementation domimpl = new XMLDOMImplementation(); domimpl.setAttribute(XMLDocument.SCALABLE_DOM, Boolean.TRUE); XMLDocument currentDoc = (XMLDocument) domimpl.createDocument(reader);
DOM2Namespace.java
プログラムは、パーサーの単純な使用方法とDOM APIへの名前空間による拡張を示します。プログラムは、XML文書を受け取って解析し、文書内の要素と属性を出力します。
「基本的なDOM解析の実行」の最初の4つの手順(パーサー作成からgetDocument()
コールまで)は、基本的にDOM2Namespace.java
の場合と同じです。主な違いは、DOMツリーの出力の手順です(手順5)。DOM2Namespace.java
プログラムでは、かわりに次の処理を行います。
// Print document elements printElements(doc); // Print document element attributes System.out.println("The attributes of each element are: "); printElementAttributes(doc);
DOM2Namespace.java
により実装されるprintElements()
メソッドは、getElementsByTagName()
をコールして、DOMツリー内のすべての要素のリストを取得します。次に、リスト内の各アイテムをループし、各Element
をnsElement
にキャストします。各nsElement
について、nsElement.getPrefix()
をコールして名前空間の接頭辞を取得し、nsElement.getLocalName()
をコールしてローカル名を取得し、nsElement.getNamespaceURI()
をコールして名前空間URIを取得します。
static void printElements(Document doc) { NodeList nl = doc.getElementsByTagName("*"); Element nsElement; String prefix; String localName; String nsName; System.out.println("The elements are: "); for (int i=0; i < nl.getLength(); i++) { nsElement = (Element)nl.item(i); prefix = nsElement.getPrefix(); System.out.println(" ELEMENT Prefix Name :" + prefix); localName = nsElement.getLocalName(); System.out.println(" ELEMENT Local Name :" + localName); nsName = nsElement.getNamespaceURI(); System.out.println(" ELEMENT Namespace :" + nsName); } System.out.println(); }
printElementAttributes()
メソッドは、Document.getElementsByTagName()
をコールして、DOMツリー内の要素のNodeList
を取得します。次に、各要素をループし、Element.getAttributes()
をコールして要素の属性のリストをNamedNodeMap
という特殊なリストとして取得します。属性リストの各アイテムについて、nsAttr.getPrefix()
をコールして名前空間の接頭辞を取得し、nsAttr.getLocalName()
をコールしてローカル名を取得し、nsAttr.getValue()
をコールして値を取得します。
static void printElementAttributes(Document doc) { NodeList nl = doc.getElementsByTagName("*"); Element e; Attr nsAttr; String attrpfx; String attrname; String attrval; NamedNodeMap nnm; int i, len; len = nl.getLength(); for (int j=0; j < len; j++) { e = (Element) nl.item(j); System.out.println(e.getTagName() + ":"); nnm = e.getAttributes(); if (nnm != null) { for (i=0; i < nnm.getLength(); i++) { nsAttr = (Attr) nnm.item(i); attrpfx = nsAttr.getPrefix(); attrname = nsAttr.getLocalName(); attrval = nsAttr.getNodeValue(); System.out.println(" " + attrpfx + ":" + attrname + " = " + attrval); } } System.out.println(); } }
EventSample.java
プログラムは、イベント・リスナーを使用して様々なイベントを登録する方法を示します。たとえば、指定されたDOM要素にノードが追加された場合は、イベントがトリガーされます。これにより、リスナーがイベントに関する情報を出力します。
プログラムは次の手順を実行します。
イベント・リスナーをインスタンス化します。登録された変更によりイベントがトリガーされると、このイベントがイベント・リスナーに渡されて処理されます。EventSample.java
の次のコード部分は、リスナーの実装を示します。
eventlistener evtlist = new eventlistener(); ... class eventlistener implements EventListener { public eventlistener(){} public void handleEvent(Event e) { String s = " Event "+e.getType()+" received " + "\n"; s += " Event is cancelable :"+e.getCancelable()+"\n"; s += " Event is bubbling event :"+e.getBubbles()+"\n"; s += " The Target is " + ((Node)(e.getTarget())).getNodeName() + "\n\n"; System.out.println(s); } }
新規XMLDocument
をインスタンス化し、getImplementation()
をコールしてDOMImplementation
オブジェクトを取得します。hasFeature()
メソッドをコールして、この実装でサポートされる機能を判断できます。EventSample.java
の次のコード部分は、この方法を示します。
XMLDocument doc1 = new XMLDocument(); DOMImplementation impl = doc1.getImplementation(); System.out.println("The impl supports Events "+ impl.hasFeature("Events", "2.0")); System.out.println("The impl supports Mutation Events "+ impl.hasFeature("MutationEvents", "2.0"));
目的のイベントをリスナーに登録します。EventSample.java
の次のコード部分は、文書ノードの3つのイベントを登録します。
doc1.addEventListener("DOMNodeRemoved", evtlist, false); doc1.addEventListener("DOMNodeInserted", evtlist, false); doc1.addEventListener("DOMCharacterDataModified", evtlist, false);
EventSample.java
の次のコード部分は、タイプXMLElement
のノードを作成し、このノードの3つのイベントを登録します。
XMLElement el = (XMLElement)doc1.createElement("element"); ... el.addEventListener("DOMNodeRemoved", evtlist, false); el.addEventListener("DOMNodeRemovedFromDocument", evtlist, false); el.addEventListener("DOMCharacterDataModified", evtlist, false); ...
イベントをトリガーするアクションを実行します。これらのイベントは、リスナーに渡されて処理されます。EventSample.java
の次のコード部分は、この方法を示します。
att.setNodeValue("abc"); el.appendChild(el1); el.appendChild(text); text.setNodeValue("xyz"); doc1.removeChild(el);
W3C DOM仕様によると、範囲はDocument
、DocumentFragment
またはAttr
のコンテンツの範囲を識別します。範囲の開始と終了に対応する1組の境界点の間にあるコンテンツを選択します。表4-8に、XMLDocument
を介してアクセスできる有用な範囲メソッドを示します。
表4-8 Rangeクラスの有用なメソッド
メソッド | 説明 |
---|---|
|
範囲のコンテンツを複製します。 |
|
範囲のコンテンツを削除します。 |
|
範囲が閉じている場合に |
|
範囲が終了するノードを取得します。 |
|
範囲が開始するノードを取得します。 |
|
ノードとそのコンテンツを選択します。 |
|
ノード内のコンテンツを選択します。 |
|
範囲の終了を示す属性を設定します。 |
|
範囲の開始を示す属性を設定します。 |
DOMRangeSample.java
プログラムは、範囲に対して行える操作をいくつか示します。
「基本的なDOM解析の実行」の最初の4つの手順(パーサー作成からgetDocument()
コールまで)は、DOMRangeSample.java
の場合と同じです。DOMRangeSample.java
プログラムは、次の手順に従って進みます。
getDocument()
をコールしてXMLDocument
を作成した後で、createRange()
で範囲オブジェクトを作成し、setStart()
およびsetEnd()
をコールしてその境界を設定します。DOMRangeSample.java
の次のコード部分は、この方法を示します。
XMLDocument doc = parser.getDocument(); ... Range r = (Range) doc.createRange(); XMLNode c = (XMLNode) doc.getDocumentElement(); // set the boundaries r.setStart(c,0); r.setEnd(c,1);
XMLDocument
メソッドをコールして範囲に関する情報を取得し、そのコンテンツを操作します。表4-8に、有用なメソッドを示します。DOMRangeSample.java
の次のコード部分は、現在のノードのコンテンツを選択して出力します。
r.selectNodeContents(c); System.out.println(r.toString());
次のコード部分は、範囲のコンテンツのクローンを作成して出力します。
XMLDocumentFragment df =(XMLDocumentFragment) r.cloneContents(); df.print(System.out);
次のコード部分は、範囲の開始コンテナと終了コンテナを取得して出力します。
c = (XMLNode) r.getStartContainer(); System.out.println(c.getText()); c = (XMLNode) r.getEndContainer(); System.out.println(c.getText());
この項では、デモ・プログラムの一部の機能のみを説明しています。詳細は、デモ・プログラム自体を参照してください。
W3C DOMレベル2 Traversal and Range仕様は、NodeFilter
およびTreeWalker
インタフェースを定義しています。XDKには次に示すインタフェースの実装が含まれます。
ノード・フィルタは、特定のタイプのNode
オブジェクトをフィルタ処理するオブジェクトです。たとえば、エンティティ参照ノードをフィルタ処理によって除外し、要素ノードと属性ノードを受け入れることができます。NodeFilter
インタフェースを実装し、次にNode
オブジェクトをacceptNode()
メソッドに渡すことにより、ノード・フィルタを作成します。通常、acceptNode()
メソッド実装はgetNodeType()
をコールしてノードのタイプを取得し、それをELEMENT_TYPE
やATTRIBUTE_TYPE
などの静的変数と比較してから、結果に基づいて表4-9の静的フィールドの1つを戻します。
表4-9 NodeFilterインタフェースの静的フィールド
メソッド | 説明 |
---|---|
|
ノードを受け入れます。 |
|
ノードを拒否します。 |
|
この単一ノードをスキップします。 |
TreeWalker
オブジェクトを使用し、whatToShow
フラグおよびフィルタ(存在する場合)で定義されている文書のビューを使用して文書ツリーまたはサブツリーを検索できます。XMLDocument.createTreeWalker()
メソッドを使用して、次の項目を指定することによりTreeWalker
オブジェクトを作成できます。
ツリーのルート・ノード
論理ビューに含める必要のあるノードのタイプを管理するフラグ
ノードをフィルタ処理するためのフィルタ
エンティティ参照とその子孫を含める必要があるかどうかを決定するフラグ
表4-10に、org.w3c.dom.traversal.TreeWalker
インタフェースの有用なメソッドを示します。
表4-10 TreeWalkerインタフェースの有用なメソッド
メソッド | 説明 |
---|---|
|
ツリー・ウォーカーを現在のノードの最初に表示可能な子に移動し、新規ノードを戻します。現在のノードに表示可能な子がない場合は、 |
|
作成時の指定に従って、ツリー・ウォーカーのルート・ノードを取得します。 |
|
ツリー・ウォーカーを現在のノードの最後に表示可能な子に移動し、新規ノードを戻します。現在のノードに表示可能な子がない場合は、 |
|
ツリー・ウォーカーを文書内の現在のノードとの相対順序で次に表示可能な子に移動し、新規ノードを戻します。 |
TreeWalkerSample.java
プログラムは、ノード・フィルタとツリー検索で行える操作をいくつか示します。
「基本的なDOM解析の実行」の最初の4つの手順(パーサー作成からgetDocument()
コールまで)は、TreeWalkerSample.java
の場合と同じです。TreeWalkerSample.java
プログラムは、次の手順に従って進みます。
ノード・フィルタ・オブジェクトを作成します。NodeFilter
インタフェースを実装するnf
クラスのacceptNode()
メソッドは、getNodeType()
を起動してノードのタイプを取得します。TreeWalkerSample.java
の次のコード部分は、この方法を示します。
NodeFilter n2 = new nf(); ... class nf implements NodeFilter { public short acceptNode(Node node) { short type = node.getNodeType(); if ((type == Node.ELEMENT_NODE) || (type == Node.ATTRIBUTE_NODE)) return FILTER_ACCEPT; if ((type == Node.ENTITY_REFERENCE_NODE)) return FILTER_REJECT; return FILTER_SKIP; } }
XMLDocument.createTreeWalker()
メソッドを起動してツリー・ウォーカーを作成します。TreeWalkerSample.java
の次のコード部分は、XMLDocument
のルート・ノードをツリー・ウォーカーのルート・ノードとして使用し、ツリー内のすべてのノードを含めます。
XMLDocument doc = parser.getDocument(); ... TreeWalker tw = doc.createTreeWalker(doc.getDocumentElement(),NodeFilter.SHOW_ALL,n2,true);
TreeWalker
オブジェクトのルート要素を取得します。次のコード部分は、この方法を示します。
XMLNode nn = (XMLNode)tw.getRoot();
ツリーを検索します。次のコード部分は、TreeWalker.nextNode()
メソッドをコールすることで文書内の順序に従ってツリーを移動する方法を示します。
while (nn != null) { System.out.println(nn.getNodeName() + " " + nn.getNodeValue()); nn = (XMLNode)tw.nextNode(); }
次のコード部分は、firstChild()
メソッドをコールすることでツリーの左側を検索する方法を示します(lastChild()
メソッドをコールすることで、ツリーの右側を検索できます)。
while (nn != null) { System.out.println(nn.getNodeName() + " " + nn.getNodeValue()); nn = (XMLNode)tw.firstChild(); }
この項では、デモ・プログラムの一部の機能のみを説明しています。詳細は、デモ・プログラム自体を参照してください。
SAXは、イベントベースのXML解析用の標準インタフェースです。この項の内容は次のとおりです。
レベル1およびレベル2のバージョンでリリースされたSAX APIは、インタフェースとクラスの集合です。APIは次のカテゴリに分類できます。
Oracle XML Parserで実装されているインタフェース。
アプリケーションに実装する必要のあるインタフェース。表4-11に、SAX 2.0のインタフェースを示します。
表4-11 SAX2ハンドラ・インタフェース
インタフェース | 説明 |
---|---|
|
XMLパーサーから通知を受信します。XMLタグを認識する際の主要なイベント処理メソッドは、 |
|
XML文書内のDTD宣言に関する通知を受信します。 |
|
通知および未解析(バイナリ)エンティティを処理します。 |
|
文書内のURIのリダイレクションの実行に必要です。 |
|
パーサー・エラーを処理します。プログラムは、様々な解析エラーに対してメソッド |
|
コメントやCDATAセクション境界などの字句情報に関する通知を受信します。 |
標準SAXクラス。
org.xml.sax.helper
内のその他のJavaクラス。SAX 2.0ヘルパー・クラスは次のとおりです。
AttributeImpl
は、AttributeList
の永続コピーを作成します。
DefaultHandler
は、表4-11に示したSAX2ハンドラ・インタフェースをデフォルトで実装したベース・クラスです。
LocatorImpl
は、解析中の指定されたポイントでロケータの値の永続スナップショットを作成します。
NamespaceSupport
は、XML名前空間のサポートを追加します。
XMLFilterImpl
は、イベントのストリームを変更する必要のあるアプリケーションで使用されるベース・クラスです。
XMLReaderFactory
は、SAXパーサーの動的なロードをサポートします。
nul
パッケージ内のデモンストレーション・クラス。
図4-5に、SAXパーサーの作成方法と、そのパーサーを使用して入力文書を解析する方法を示します。
SAXを使用した入力XML文書の解析の基本ステージは次のとおりです。
SAXParser
オブジェクトを作成し、そのプロパティを構成します(有用なプロパティ・メソッドは、表4-5を参照)。たとえば、パーサーの検証モードを設定します。
イベント・ハンドラをインスタンス化します。プログラムでは、表4-11のハンドラ・インタフェースの実装を提供する必要があります。
イベント・ハンドラをパーサーに登録します。イベント・ハンドラをパーサーに登録し、特定のイベントの発生時に起動するメソッドをパーサーが認識できるようにする必要があります。表4-12に、SAXParser
で使用できる登録メソッドを示します。
表4-12 イベント・ハンドラを登録するためのSAXParserのメソッド
メソッド | メソッドの用途 |
---|---|
|
コンテンツ・イベント・ハンドラをアプリケーションに登録します。 |
|
DTDイベント・ハンドラを登録します。アプリケーションでDTDハンドラを登録しない場合、SAXパーサーにより報告されるすべてのDTDイベントは無視され、警告は出力されません。アプリケーションでは、解析の途中で新規または別のハンドラを登録できます。SAXパーサーはただちに新規ハンドラの使用を開始します。 |
|
エラー・イベント・ハンドラをアプリケーションに登録します。アプリケーションでエラー・ハンドラを登録しない場合、SAXパーサーにより報告されるすべてのエラー・イベントは無視され、警告は出力されません。ただし、正常な処理が続行されない場合があります。予期しない不具合を回避するために、すべてのSAXアプリケーションでエラー・ハンドラを実装することを強くお薦めします。アプリケーションでは、解析の途中で新規または別のハンドラを登録できます。SAXパーサーはただちに新規ハンドラの使用を開始します。 |
|
エンティティ・リゾルバをアプリケーションに登録します。アプリケーションでエンティティ・リゾルバを登録しない場合、 |
SAXParser.parse()
メソッドを使用して入力文書を解析します。すべてのSAXインタフェースは、同期操作を前提としています。そのため、解析メソッドは解析が完了するまで結果を戻しません。リーダーは、次のイベントを通知する前にイベント・ハンドラのコールバックが結果を戻すまで待機する必要があります。
SAXParser.parse()
メソッドがコールされた場合、プログラムでは、アプリケーションで実装された複数のコールバック・メソッドの1つを起動します。メソッドは、イベント・ハンドラで実装されたContentHandler
、ErrorHandler
、DTDHandler
およびEntityResolver
インタフェースにより定義されます。たとえば、アプリケーションは、開始要素を検出した際にstartElement()
メソッドをコールできます。
SAXSample.java
プログラムは、SAX解析の基本手順を示します。SAXSample
クラスはHandlerBase
を拡張します。プログラムは、入力としてXMLファイルを受け取って解析し、ファイルのコンテンツに関する情報を出力します。
プログラムは次の手順を実行します。
Locator
を格納します。Locator
は、SAXイベントを文書の場所に関連付けます。SAXパーサーは、Locator
インスタンスをコンテンツ・ハンドラのsetDocumentLocator()
メソッドに渡すことにより、アプリケーションに場所情報を提供します。アプリケーションでは、オブジェクトを使用して、XMLソース文書内の他の任意のコンテンツ・ハンドラ・イベントの場所を取得できます。SAXSample.java
の次のコード部分は、この方法を示します。
Locator locator;
新規イベント・ハンドラをインスタンス化します。SAXSample.java
の次のコード部分は、この方法を示します。
SAXSample sample = new SAXSample();
SAXパーサーをインスタンス化し、構成します。SAXSample.java
の次のコード部分は、モードをDTD検証に設定します。
Parser parser = new SAXParser(); ((SAXParser)parser).setValidationMode(SAXParser.DTD_VALIDATION);
SAXパーサーにイベント・ハンドラを登録します。SAXParser
クラスの登録メソッドを使用できますが、ハンドラ・インタフェースはユーザーが実装する必要があります。次のコード部分は、ハンドラを登録します。
parser.setDocumentHandler(sample); parser.setEntityResolver(sample); parser.setDTDHandler(sample); parser.setErrorHandler(sample);
次のコードは、DocumentHandler
インタフェースの実装をいくつか示します。
public void setDocumentLocator (Locator locator) { System.out.println("SetDocumentLocator:"); this.locator = locator; } public void startDocument() { System.out.println("StartDocument"); } public void endDocument() throws SAXException { System.out.println("EndDocument"); } public void startElement(String name, AttributeList atts) throws SAXException { System.out.println("StartElement:"+name); for (int i=0;i<atts.getLength();i++) { String aname = atts.getName(i); String type = atts.getType(i); String value = atts.getValue(i); System.out.println(" "+aname+"("+type+")"+"="+value); } } ...
次のコードは、EntityResolver
インタフェースの実装を示します。
public InputSource resolveEntity (String publicId, String systemId) throws SAXException { System.out.println("ResolveEntity:"+publicId+" "+systemId); System.out.println("Locator:"+locator.getPublicId()+" locator.getSystemId()+ " "+locator.getLineNumber()+" "+locator.getColumnNumber()); return null; }
次のコードは、DTDHandler
インタフェースの実装を示します。
public void notationDecl (String name, String publicId, String systemId) { System.out.println("NotationDecl:"+name+" "+publicId+" "+systemId); } public void unparsedEntityDecl (String name, String publicId, String systemId, String notationName) { System.out.println("UnparsedEntityDecl:"+name + " "+publicId+" "+ systemId+" "+notationName); }
次のコードは、ErrorHandler
インタフェースの実装を示します。
public void warning (SAXParseException e) throws SAXException { System.out.println("Warning:"+e.getMessage()); } public void error (SAXParseException e) throws SAXException { throw new SAXException(e.getMessage()); } public void fatalError (SAXParseException e) throws SAXException { System.out.println("Fatal error"); throw new SAXException(e.getMessage()); }
入力XML文書を解析します。次のコード部分は、文書をURLに変換して解析します。
parser.parse(DemoUtil.createURL(argv[0]).toString());
この項では、SAX2Namespace.java
サンプル・プログラムについて説明します。このサンプル・プログラムは、XMLDefaultHandler
というイベント・ハンドラをorg.xml.sax.helpers.DefaultHandler
クラスのサブクラスとして実装します。ContentHandler
インタフェースを実装する最も簡単な方法は、org.xml.sax.helpers.DefaultHandler
クラスを拡張することです。DefaultHandler
クラスは、イベントを処理するためのデフォルトの動作をいくつか提供しますが、一般的な動作は何も行わないことです。
SAX2Namespace.java
プログラムは、対象のイベントに対してのみメソッドをオーバーライドします。具体的には、XMLDefaultHandler
クラスはstartElement()
およびendElement()
という2つのメソッドのみ実装します。startElement
イベントは、SAXParser
がXML文書内に新規要素を検出するたびにトリガーされます。このイベントがトリガーされると、startElement()
メソッドは要素の名前空間情報を出力します。
SAX2Namespace.java
サンプル・プログラムは次の手順を実行します。
DefaultHandler
型の新規イベント・ハンドラをインスタンス化します。次のコード部分は、この方法を示します。
DefaultHandler defHandler = new XMLDefaultHandler();
SAXパーサーを作成し、その検証モードを設定します。SAXSample.java
の次のコード部分は、モードをDTD検証に設定します。
Parser parser = new SAXParser(); ((SAXParser)parser).setValidationMode(SAXParser.DTD_VALIDATION);
SAXパーサーにイベント・ハンドラを登録します。次のコード部分は、入力文書、DTD、エンティティおよびエラーのハンドラを登録します。
parser.setContentHandler(defHandler); parser.setEntityResolver(defHandler); parser.setDTDHandler(defHandler); parser.setErrorHandler(defHandler);
次のコードは、XMLDefaultHandler
実装を示します。startElement()
およびendElement()
メソッドは、各要素の修飾名、ローカル名および名前空間URIを出力します(これらの用語の説明は、表4-7を参照)。
class XMLDefaultHandler extends DefaultHandler { public void XMLDefaultHandler(){} public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { System.out.println("ELEMENT Qualified Name:" + qName); System.out.println("ELEMENT Local Name :" + localName); System.out.println("ELEMENT Namespace :" + uri); for (int i=0; i<atts.getLength(); i++) { qName = atts.getQName(i); localName = atts.getLocalName(i); uri = atts.getURI(i); System.out.println(" ATTRIBUTE Qualified Name :" + qName); System.out.println(" ATTRIBUTE Local Name :" + localName); System.out.println(" ATTRIBUTE Namespace :" + uri); // You can get the type and value of the attributes either // by index or by the Qualified Name. String type = atts.getType(qName); String value = atts.getValue(qName); System.out.println(" ATTRIBUTE Type :" + type); System.out.println(" ATTRIBUTE Value :" + value); System.out.println(); } } public void endElement(String uri, String localName, String qName) throws SAXException { System.out.println("ELEMENT Qualified Name:" + qName); System.out.println("ELEMENT Local Name :" + localName); System.out.println("ELEMENT Namespace :" + uri); } }
入力XML文書を解析します。次のコード部分は、文書をURLに変換して解析します。
parser.parse(DemoUtil.createURL(argv[0]).toString());
単純なSAXパーサーをXMLTokenizer
クラスのインスタンスとして作成し、パーサーを使用して入力XMLをトークン化できます。表4-13に、このクラスの有用なメソッドを示します。
表4-13 XMLTokenizerのメソッド
メソッド | 説明 |
---|---|
|
XMLトークン化機能の新規トークンを登録します。 |
|
エラーの出力ストリームを登録します。 |
|
入力XMLをトークン化します。 |
Tokenizer
機能のあるSAXパーサーは、XMLToken
インタフェースを実装します。XMLToken
のコールバック・メソッドはtoken()
です。このメソッドは、XMLトークンおよび対応する値を受け取り、アクションを実行します。たとえば、トークン名に続いてトークンの値を出力するようにtoken()
を実装できます。
Tokenizer.java
プログラムは、入力としてXML文書を受け取って解析し、XMLトークンのリストを出力します。プログラムでは、次の処理を行うdoParse()
メソッドを実装します。
入力XMLストリームからURLを作成します。
URL url = DemoUtil.createURL(arg);
次のようにXMLTokenizer
パーサーを作成します。
parser = new XMLTokenizer ((XMLToken)new Tokenizer());
次のように出力エラー・ストリームを登録します。
parser.setErrorStream (System.out);
トークンをパーサーに登録します。Tokenizer.java
の次のコード部分は、登録されたトークンをいくつか示します。
parser.setToken (STagName, true); parser.setToken (EmptyElemTag, true); parser.setToken (STag, true); parser.setToken (ETag, true); parser.setToken (ETagName, true); ...
XML文書を次のようにトークン化します。
parser.tokenize (url);
token()
コールバック・メソッドは、特定のトークンが検出されたときに実行するアクションを判断します。Tokenizer.java
の次のコード部分は、このメソッドの実装の一部を示します。
public void token (int token, String value) { switch (token) { case XMLToken.STag: System.out.println ("STag: " + value); break; case XMLToken.ETag: System.out.println ("ETag: " + value); break; case XMLToken.EmptyElemTag: System.out.println ("EmptyElemTag: " + value); break; case XMLToken.AttValue: System.out.println ("AttValue: " + value); break; ... default: break; } }
JAXPを使用すると、JavaプログラムでSAXおよびDOMパーサーとXSLTプロセッサを使用できます。この項の内容は次のとおりです。
表4-14に示すJAXP APIは、パーサーをプラッガブルにするためのシン・レイヤーを提供する抽象クラスで構成されたAPI構造を持ちます。Oracleは、Sun社のリファレンス実装に基づいてJAXPを実装しています。
表4-14 JAXPパッケージ
パッケージ | 説明 |
---|---|
|
DOM 2.0およびSAX 1.0パーサーの標準APIを提供します。パッケージには、 |
|
XML変換の処理と、ソースから結果への変換の実行のための汎用APIを定義します。 |
|
DOM固有の変換APIを提供します。 |
|
SAX2固有の変換APIを提供します。 |
|
ストリーム固有およびURI固有の変換APIを提供します。 |
ファクトリ設計パターンに依存して、JAXPを使用して新規SAXパーサー・エンジンを作成できます。図4-6に、基本プロセスを示します。
JAXPを介したSAXでの解析の基本手順は、次のとおりです。
SAXParserFactory
クラスで新規SAXパーサー・ファクトリを作成します。
ファクトリを構成します。
新規SAXパーサー(SAXParser
)オブジェクトをファクトリから作成します。
SAXパーサーのイベント・ハンドラを設定します。
入力XML文書を解析します。
ファクトリ設計パターンに基づき、JAXPを使用して新規DOM文書ビルダー・エンジンを作成できます。図4-7に、基本プロセスを示します。
JAXPを介したDOMでの解析の基本手順は、次のとおりです。
DocumentBuilderFactory
クラスで新規DOMパーサー・ファクトリを作成します。
ファクトリを構成します。
新規DOMビルダー(DocumentBuilder
)オブジェクトをファクトリから作成します。
DOMビルダーのエラー・ハンドラとエンティティ・リゾルバを設定します。
入力XML文書を解析します。
JAXPExamples.java
プログラムは、JAXPを使用した解析の基本手順を示します。このプログラムは、次のメソッドを実装し、これらのメソッドを使用して/jaxp
ディレクトリ内のXMLファイルに対して解析および追加処理を実行します。
basic()
identity()
namespaceURI()
templatesHandler()
contentHandler2contentHandler()
contentHandler2DOM()
reader()
xmlFilter()
xmlFilterChain()
プログラムでは、サンプルXMLファイルjaxpone.xml
およびjaxpone.xsl
のURLを作成し、前述のメソッドを順番にコールします。デモの基本設計は次のとおりです(スペースを節約するために、basic()
メソッドのみ示しています)。
public class JAXPExamples { public static void main(String argv[]) throws TransformerException, TransformerConfigurationException, IOException, SAXException, ParserConfigurationException, FileNotFoundException { try { URL xmlURL = createURL("jaxpone.xml"); String xmlID = xmlURL.toString(); URL xslURL = createURL("jaxpone.xsl"); String xslID = xslURL.toString(); // System.out.println("--- basic ---"); basic(xmlID, xslID); System.out.println(); ... } catch(Exception err) { err.printStackTrace(); } } // public static void basic(String xmlID, String xslID) throws TransformerException, TransformerConfigurationException { TransformerFactory tfactory = TransformerFactory.newInstance(); Transformer transformer = tfactory.newTransformer(new StreamSource(xslID)); StreamSource source = new StreamSource(xmlID); transformer.transform(source, new StreamResult(System.out)); } ... }
JAXPExamples.java
プログラムのreader()
メソッドは、SAXを使用してXML文書を解析するための簡単な方法を示します。このメソッドは次の手順を実行します。
TransformerFactory
の新規インスタンスを作成し、SAXTransformerFactory
にキャストします。アプリケーションでは、SAXファクトリを使用して、SAXパーサー・インスタンスを構成および取得できます。次に例を示します。
TransformerFactory tfactory = TransformerFactory.newInstance(); SAXTransformerFactory stfactory = (SAXTransformerFactory)tfactory;
スタイルシートからStreamSource
オブジェクトを作成し、それをファクトリ・メソッドnewXMLFilter()
に渡すことにより、XMLリーダーを作成します。このメソッドは、指定されたSource
を変換命令として使用するXMLFilter
オブジェクトを戻します。次に例を示します。
URL xslURL = createURL("jaxpone.xsl"); String xslID = xslURL.toString(); ... StreamSource streamSource = new StreamSource(xslID); XMLReader reader = stfactory.newXMLFilter(streamSource);
コンテンツ・ハンドラを作成し、XMLリーダーに登録します。次の例では、クラスoraContentHandler
のインスタンスを作成します。このインスタンスは、デモ・ディレクトリ内のoraContentHandler.java
プログラムをコンパイルすることで作成されます。
ContentHandler contentHandler = new oraContentHandler(); reader.setContentHandler(contentHandler);
次のコード部分は、oraContentHandler
クラスの実装の一部を示します。
public class oraContentHandler implements ContentHandler { private static final String TRADE_MARK = "Oracle 9i "; public void setDocumentLocator(Locator locator) { System.out.println(TRADE_MARK + "- setDocumentLocator"); } public void startDocument() throws SAXException { System.out.println(TRADE_MARK + "- startDocument"); } public void endDocument() throws SAXException { System.out.println(TRADE_MARK + "- endDocument"); } ...
InputSource
をXMLReader.parse()
メソッドに渡すことにより、入力XML文書を解析します。次に例を示します。
InputSource is = new InputSource(xmlID); reader.parse(is);
JAXPを使用して、インタフェースSource
の任意のクラスをインタフェースResult
のクラスに変換できます。表4-15に、いくつかの変換例を示します。
表4-15 JAXPを使用したクラスの変換
JAXPを使用して変換するクラス | 変換先クラス |
---|---|
|
|
|
|
|
|
これらの変換は、次のタイプの入力を受け入れます。
XML文書
スタイルシート
oraContentHandler.java
で定義されたContentHandler
クラス
たとえば、identity()
メソッドを使用して、出力XML文書が入力XML文書と同じになる変換を実行できます。xmlFilterChain()
メソッドを使用して、連鎖内の3つのスタイルシートを適用できます。
basic()
メソッドは、基本的なXSLT変換の実行方法を示します。メソッドは次の手順を実行します。
TransformerFactory
の新規インスタンスを作成します。次に例を示します。
TransformerFactory tfactory = TransformerFactory.newInstance();
ファクトリから新規XSLトランスフォーマを作成し、変換に使用するスタイルシートを指定します。次の例では、jaxpone.xsl
スタイルシートを指定します。
URL xslURL = createURL("jaxpone.xsl"); String xslID = xslURL.toString(); . . . Transformer transformer = tfactory.newTransformer(new StreamSource(xslID));
ストリーム・ソースを入力XML文書に設定します。basic()
メソッドの次の部分は、ストリーム・ソースをjaxpone.xml
に設定します。
URL xmlURL = createURL("jaxpone.xml"); String xmlID = xmlURL.toString(); . . . StreamSource source = new StreamSource(xmlID);
StreamSource
の文書をStreamResult
に変換します。次の例では、StreamSource
をStreamResult
に変換します。
transformer.transform(source, new StreamResult(System.out));
Oracle XDKでは、SAXまたはDOMを使用してXMLを解析し、解析したデータを圧縮バイナリ・ストリームに書き込むことができます。次に、プロセスを反転し、XMLデータを再構築できます。この項の内容は次のとおりです。
DOMCompression.java
およびDOMDeCompression.java
プログラムは、DOMの圧縮と解凍の基本手順を示します。最も重要なDOM圧縮メソッドは次のとおりです。
XMLDocument.writeExternal()
は、オブジェクトに関する情報でバイナリ圧縮ストリームを作成することにより、オブジェクトの状態を保存します。
XMLDocument.readExternal()
は、writeExternal()
メソッドにより圧縮ストリームに書き込まれた情報を読み取り、オブジェクトを復元します。
シリアライズの基本的な方法は、XML文書を解析してXMLDocument
を作成し、ObjectOutputStream
を初期化し、さらにXMLDocument.writeExternal()
をコールして圧縮ストリームを書き込むことです。
DOMCompression.java
プログラムは次の手順を実行します。
DOMパーサーを作成し、入力XML文書を解析し、DOM表現を取得します。この方法は、「基本的なDOM解析の実行」で説明しています。DOMCompression.java
の次のコード部分は、この方法を示します。
public class DOMCompression { static OutputStream out = System.out; public static void main(String[] args) { XMLDocument doc = new XMLDocument(); DOMParser parser = new DOMParser(); try { parser.setValidationMode(XMLParser.SCHEMA_VALIDATION); parser.setPreserveWhitespace(false); parser.retainCDATASection(true); parser.parse(createURL(args[0])); doc = parser.getDocument(); ...
FileOutputStream
を作成し、シリアライズのためにObjectOutputStream
にラップします。次のコード部分は、xml.ser
出力ファイルを作成します。
OutputStream os = new FileOutputStream("xml.ser"); ObjectOutputStream oos = new ObjectOutputStream(os);
XMLDocument.writeExternal()
をコールして、オブジェクトをファイルにシリアライズします。このメソッドは、このオブジェクトに関する情報でバイナリ圧縮ストリームを作成することにより、オブジェクトの状態を保存します。この方法を示す文は次のとおりです。
doc.writeExternal(oos);
解凍の基本的な方法は、ObjectInputStream
オブジェクトを作成し、XMLDocument.readExternal()
をコールして圧縮ストリームを読み取ることです。DOMDeCompression.java
プログラムは次の手順を実行します。
圧縮ファイルのファイル入力ストリームを作成し、ObjectInputStream
にラップします。DOMDeCompression.java
の次のコード部分は、前の項で作成した圧縮ファイルからFileInputStream
を作成します。
InputStream is; ObjectInputStream ois; ... is = new FileInputStream("xml.ser"); ois = new ObjectInputStream(is);
新規XML文書オブジェクトを作成して、解凍したデータを格納します。次のコード部分は、この方法を示します。
XMLDocument serializedDoc = null; serializedDoc = new XMLDocument();
XMLDocument.readExternal()
をコールして、圧縮ファイルを読み取ります。次のコード部分は、データを読み取ってSystem.out
に出力します。
serializedDoc.readExternal(ois); serializedDoc.print(System.out);
SAXCompression.java
プログラムは、SAXを使用してファイルを解析し、圧縮ストリームをファイルに書き込み、シリアライズしたデータをファイルから読み取る基本手順を示します。重要なクラスは次のとおりです。
CXMLHandlerBase
は、SAXイベントに基づいてXMLデータを圧縮するSAX Handler
です。SAX圧縮を使用するには、このインタフェースを実装し、Parser.setDocumentHandler()
をコールしてSAXパーサーに登録します。
CXMLParser
は、圧縮ストリームからSAXイベントを再生成するXMLパーサーです。
シリアライズの基本的な方法は、SAXパーサーにCXMLHandlerBase
ハンドラを登録し、ObjectOutputStream
を初期化し、入力XMLを解析することです。SAXCompression.java
プログラムは次の手順を実行します。
FileOutputStream
を作成し、ObjectOutputStream
にラップします。SAXCompression.java
の次のコード部分は、xml.ser
ファイルを作成します。
String compFile = "xml.ser"; FileOutputStream outStream = new FileOutputStream(compFile); ObjectOutputStream out = new ObjectOutputStream(outStream);
SAXイベント・ハンドラを作成します。CXMLHandlerBase
クラスは、ContentHandler
、DTDHandler
、EntityResolver
およびErrorHandler
インタフェースを実装します。次のコード部分は、この方法を示します。
CXMLHandlerBase cxml = new CXMLHandlerBase(out);
SAXパーサーを作成します。次のコード部分は、この方法を示します。
SAXParser parser = new SAXParser();
SAXパーサーを構成します。次のコード部分は、コンテンツ・ハンドラとエンティティ・リゾルバを設定し、検証モードも設定します。
parser.setContentHandler(cxml); parser.setEntityResolver(cxml); parser.setValidationMode(XMLConstants.NONVALIDATING);
oracle.xml.comp.CXMLHandlerBase
はDocumentHandler
とContentHandler
の両方のインタフェースを実装しますが、SAX 2.0 ContentHandler
インタフェースの使用が推奨されることに注意してください。
XMLを解析します。プログラムは、シリアライズされたデータをObjectOutputStream
に書き込みます。次のコード部分は、この方法を示します。
parser.parse(url);
SAXオブジェクトの非シリアライズの基本的な方法は、CXMLParser
クラスを使用してSAX圧縮パーサーを作成し、パーサーのコンテンツ・ハンドラを設定し、圧縮ストリームを解析することです。
SAXDeCompression.java
プログラムは次の手順を実行します。
SAXイベント・ハンドラを作成します。SampleSAXHandler.java
プログラムは、SAXDeCompression.java
で使用するハンドラを作成します。SAXDeCompression.java
の次のコード部分は、ハンドラ・オブジェクトを作成します。
SampleSAXHandler xmlHandler = new SampleSAXHandler();
CXMLParser
クラスをインスタンス化することにより、SAXパーサーを作成します。このクラスは、圧縮ストリームからSAXイベントを生成することにより、その圧縮ストリームからのXML文書の再生成を実装します。次のコード部分は、この方法を示します。
CXMLParser parser = new CXMLParser();
SAXパーサーのイベント・ハンドラを設定します。次のコード部分は、この方法を示します。
parser.setContentHandler(xmlHandler);
圧縮ストリームを解析し、SAXイベントを生成します。次のコードは、コマンドラインからファイル名を受け取り、XMLを解析します。
parser.parse(args[0]);
この項の内容は次のとおりです。
XMLNode
クラスのselectNodes()
メソッドを使用して、XSLが許可する選択パターンに基づいてDOMツリーまたはサブツリーからコンテンツを抽出できます。selectNodes()
のオプションの2つ目のパラメータを使用して、名前空間の接頭辞を解決できます。つまり、接頭辞付きの展開された名前空間URLを戻します。XMLElement
クラスはNSResolver
を実装するため、XMLElement
オブジェクトの参照は、2つ目のパラメータとして送信できます。XMLElement
は、入力ドキュメントに基づいて接頭辞を解決します。名前空間の定義をオーバーライドする必要がある場合、NSResolver
インタフェースを使用できます。
例4-4のサンプル・コードに、selectNodes()
の使用方法を示します。
例4-4 selectNodes()を使用したDOMツリーのコンテンツの抽出
// // selectNodesTest.java // import java.io.*; import oracle.xml.parser.v2.*; import org.w3c.dom.Node; import org.w3c.dom.Element; import org.w3c.dom.Document; import org.w3c.dom.NodeList; public class selectNodesTest { public static void main(String[] args) throws Exception { // supply an xpath expression String pattern = "/family/member/text()"; // accept a filename on the command line // run the program with $ORACLE_HOME/xdk/demo/java/parser/common/family.xml String file = args[0]; if (args.length == 2) pattern = args[1]; DOMParser dp = new DOMParser(); dp.parse(DemoUtil.createURL(file)); // include createURL from DemoUtil XMLDocument xd = dp.getDocument(); XMLElement element = (XMLElement) xd.getDocumentElement(); NodeList nl = element.selectNodes(pattern, element); for (int i = 0; i < nl.getLength(); i++) { System.out.println(nl.item(i).getNodeValue()); } // end for } // end main } // end selectNodesTest
プログラムをテストするには、例4-4のコードを使用してファイルを作成してから、$ORACLE_HOME/xdk/demo/java/parser/
common
ディレクトリ内でコンパイルします。ファイル名family.xml
をパラメータとしてプログラムに渡して、<family>
ツリーを検索します。出力は次のようになります。
% java selectNodesTest family.xml Sarah Bob Joanne Jim
ここで、次のコードを実行して、文書内のすべての<member>
要素のmemberid
属性の値を判断します。
% java selectNodesTest family.xml //member/@memberid m1 m2 m3 m4
ユーザーがクライアント側Javaフォームに入力でき、XML文書を取得できるように、プログラムを作成する必要があると想定します。Javaプログラムには、String
型の次の変数が含まれているとします。
String firstname = "Gianfranco"; String lastname = "Pietraforte";
次のいずれかの方法を使用して、この情報をXML文書に挿入できます。
XML文書を文字列で作成し、解析します。次に例を示します。
String xml = "<person><first>"+firstname+"</first>"+ "<last>"+lastname+"</last></person>"; DOMParser d = new DOMParser(); d.parse(new StringReader(xml)); Document xmldoc = d.getDocument();
DOM APIを使用して、要素を作成して順番に追加することによりXML文書を作成します。次に例を示します。
Document xmldoc = new XMLDocument(); Element e1 = xmldoc.createElement("person"); xmldoc.appendChild(e1); Element e2 = xmldoc.createElement("firstname"); e1.appendChild(e2); Text t = xmldoc.createText("Larry"); e2.appendChild(t);
単一のDOMツリーでは2番目の方法のみ使用できることに注意してください。たとえば、例4-5に抜粋したコードを記述するとします。
例4-5 appendChild()の不適切な使用方法
XMLDocument xmldoc1 = new XMLDocument(); XMLElement e1 = xmldoc1.createElement("person"); XMLDocument xmldoc2 = new XMLDocument(); XMLElement e2 = xmldoc2.createElement("firstname"); e1.appendChild(e2);
前述のコードでは、e1
の所有者文書がxmldoc1
で、e2
の所有者がxmldoc2
であるため、XMLElement.appendChild()
をコールしたときにWRONG_DOCUMENT_ERR
のDOM例外が発生します。appendChild()
メソッドは単一ツリー内でのみ動作しますが、例4-5では2つの異なるツリーを使用しています。
異なるXML文書間におけるDOM文書のフラグメントまたはDOMノードのコピーおよび貼付けには、DOM 2で導入されたXMLDocument.importNode()
メソッドおよびDOM 3で導入されたXMLDocument.adoptNode()
メソッドを使用できます。例4-6のコマンドラインは、このタスクの実行方法を示しています。
例4-6 appendChild()を使用した文書のマージ
XMLDocument doc1 = new XMLDocument(); XMLElement element1 = doc1.createElement("person"); XMLDocument doc2 = new XMLDocument(); XMLElement element2 = doc2.createElement("firstname"); // element2 = doc1.importNode(element2); // element2 = doc1.adoptNode(element2); element1.appendChild(element2);
この項では、DTDの解析方法について説明します。この項の内容は次のとおりです。
DOMParser.parse()
メソッドをコールしてXML文書をInputStream
として解析する場合は、DOMParser.setBaseURL()
メソッドを使用してJavaプログラム内の外部DTDを認識します。このメソッドは、DTDが公開されている場所を指します。
DTDをロードして解析する方法を次の手順で説明します。
DTDをInputStream
としてロードします。たとえば、/mydir/my.dtd
外部DTDに対して文書が妥当であるかどうかを検証する必要があるとします。次のコードを使用できます。
InputStream is = MyClass.class.getResourceAsStream("/mydir/my.dtd");
このコードによって、DTDが指定されているCLASSPATH
上の最初の相対位置にある./mydir/my.dtd
が開かれます。JARファイルがCLASSPATH
にある場合は、そのJARファイルも開かれます。
DOMパーサーを作成し、検証モードを設定します。たとえば、次のコードを使用します。
DOMParser d = new DOMParser(); d.setValidationMode(DTD_VALIDATION);
DTDを解析します。次の例では、InputStream
オブジェクトをDOMParser.parseDTD()
メソッドに渡します。
d.parseDTD(is, "rootelementname");
文書タイプを取得し、設定します。getDoctype()
メソッドはDTDオブジェクトを取得し、setDoctype()
メソッドは解析に使用するDTDを設定します。次の例に、この方法を示します。
d.setDoctype(d.getDoctype());
次のコードは、別の方法を示しています。parseDTD()
メソッドを起動して、DTDファイルを個別に解析し、DTDオブジェクトを取得できます。
d.parseDTD(new FileReader("/mydir/my.dtd")); DTD dtd = d.getDoctype(); parser.setDoctype(dtd);
入力XML文書を解析します。たとえば、次のコードはmydoc.xml
を解析します。
d.parse("mydoc.xml");
XML Parser for Javaには、DOMParser.setDoctype()
メソッドを使用した検証モードと非検証モードでのDTDキャッシュ機能が用意されています。このメソッドでDTDを設定すると、パーサーはこのDTDをキャッシュして、さらに解析を実行します。DTDキャッシュ機能はオプションであり、自動的には有効にならないことに注意してください。
プログラムで、同じDTDを使用して複数のXML文書を解析する必要があると想定します。XML文書の解析後、次の例のようにパーサーからDTDを取得し、設定できます。
DOMParser parser = new DOMParser(); DTD dtd = parser.getDoctype(); parser.setDoctype(dtd);
パーサーはこのDTDをキャッシュして、後続のXML文書の解析に使用します。例4-7に、DOMParser.setDoctype()
を起動してDTDをキャッシュする方法の詳細な例を示します。
例4-7 DTDSample.java
/** * DESCRIPTION * This program illustrates DTD caching. */ import java.net.URL; import java.io.*; import org.xml.sax.InputSource; import oracle.xml.parser.v2.*; public class DTDSample { static public void main(String[] args) { try { if (args.length != 3) { System.err.println("Usage: java DTDSample dtd rootelement xmldoc"); System.exit(1); } // Create a DOM parser DOMParser parser = new DOMParser(); // Configure the parser parser.setErrorStream(System.out); parser.showWarnings(true); // Create a FileReader for the DTD file specified on the command // line and wrap it in an InputSource FileReader r = new FileReader(args[0]); InputSource inSource = new InputSource(r); // Create a URL from the command-line argument and use it to set the // system identifier inSource.setSystemId(DemoUtil.createURL(args[0]).toString()); // Parse the external DTD from the input source. The second argument is // the name of the root element. parser.parseDTD(inSource, args[1]); DTD dtd = parser.getDoctype(); // Create a FileReader object from the XML document specified on the // command line r = new FileReader(args[2]); // Wrap the FileReader in an InputSource, create a URL from the filename, // and set the system identifier inSource = new InputSource(r); inSource.setSystemId(DemoUtil.createURL(args[2]).toString()); // ******************** parser.setDoctype(dtd); // ******************** parser.setValidationMode(DOMParser.DTD_VALIDATION); // parser.setAttribute(DOMParser.USE_DTD_ONLY_FOR_VALIDATION,Boolean.TRUE); parser.parse(inSource); // Obtain the DOM tree and print XMLDocument doc = parser.getDocument(); doc.print(new PrintWriter(System.out)); } catch (Exception e) { System.out.println(e.toString()); } } }
キャッシュされたDTDオブジェクトが検証に対してのみ使用される場合は、DOMParser.USE_DTD_ONLY_FOR_VALIDATION
属性を設定します。DTDオブジェクトが検証に使用されない場合、XMLパーサーはDTDオブジェクトをコピーして、結果のDOMツリーに追加します。パーサーを次のように設定できます。
parser.setAttribute(DOMParser.USE_DTD_ONLY_FOR_VALIDATION,Boolean.TRUE);
この項の内容は次のとおりです。
オペレーティング・システム・ファイルに格納されたXMLファイルを読み取る場合は、FileReader
クラスを使用しないでください。かわりにXMLパーサーを使用して、文書の文字のエンコーディングが自動的に検出されるようにします。外部エンコーディング情報がないバイナリFileInputStream
の場合、パーサーは、バイト・オーダー・マークおよびXML文書のエンコーディング宣言に基づいて、文字のエンコーディングを自動的に判断します。AutoDetectEncoding.java
デモのサンプル・コードを使用して、サポートされている任意のエンコーディングでの任意の整形式文書を解析できます。このデモは、$ORACLE_HOME/xdk/demo/java/parser/domにあります。
注意: 仕様のとおりに、文書内で適切なエンコーディング宣言を含めます。setEncoding() では、入力文書のエンコーディングを設定できません。かわりに、出力に正しいエンコーディングを設定するためにoracle.xml.parser.v2.XMLDocument で使用されます。 |
UTF-8エンコーディングを使用して、XMLをデータベースのNCLOB
列にロードするとします。XMLには、2つのUTF-8マルチバイト文字が含まれています。
G(0xc2,0x82)otingen, Br(0xc3,0xbc)ck_W
次の処理を行うJavaストアド・ファンクションを作成します。
デフォルトの接続オブジェクトを使用して、データベースに接続します。
SELECT
問合せを実行します。
oracle.jdbc.OracleResultSet
オブジェクトを取得します。
OracleResultSet.getCLOB()
メソッドをコールします。
CLOB
オブジェクトに対してgetAsciiStream()
メソッドをコールします。
次のコードを実行してXMLをDOMオブジェクトに変換します。
DOMParser parser = new DOMParser(); parser.setPreserveWhitespace(true); parser.parse(istr); // istr getAsciiStream XMLDocument xmldoc = parser.getDocument();
プログラムは、文字(0xc2
、0x82
)が有効なUTF-8であっても、XMLに無効なUTF-8エンコーディングが含まれているということを示す例外をスローします。問題は、プログラムがOracleResultSet.getAsciiStream()
メソッドをコールするときに文字に異常が発生する可能性があることです。この問題を解決するには、getAsciiStream()
のかわりに、getUnicodeStream()
およびgetBinaryStream()
メソッドを起動します。この方法が機能しない場合は、DOMParser.parse(istr)
をコールする際に文字がパーサーに送信される前に、文字が異常でないことを確認するために出力してみてください。
FileWriter
クラスは、実行時環境のデフォルトの文字エンコーディングに依存するため、XMLファイルを作成するときに、このクラスを使用しないでください。ドキュメントにデフォルトの文字エンコーディングで使用できない文字が含まれる場合、出力ファイルでは、解析エラーやデータの損失が発生する可能性があります。
UTF-8エンコーディングはXML文書には一般的ですが、UTF-8は、通常はJavaのデフォルトのファイル・エンコーディングではありません。デフォルトのファイル・エンコーディングを想定したJavaクラスをプログラムで使用すると、問題が発生する可能性があります。これらの問題を回避するために、$ORACLE_HOME/xdk/demo/java/parser/dom
のI18nSafeXMLFileWritingSample.java
プログラムに示されている方法を使用できます。
特殊文字の出力にはSystem.out.println()
を使用できないことに注意してください。OutputStreamWriter
など、エンコーディングを識別するバイナリ出力ストリームを使用する必要があります。次の例のように、OutputStreamWriter
を構築し、write(char[]
, int
, int)
メソッドを使用して出力できます。
/* Java encoding string for ISO8859-1*/ OutputStreamWriter out = new OutputStreamWriter(System.out, "8859_1"); OutputStreamWriter.write(...);
String
に含まれているXML文書を直接解析する方法は現在はありません。文字列は、解析する前にInputStream
またはInputSource
オブジェクトに変換する必要があります。
1つの方法は、文字列内のバイトを使用するByteArrayInputStream
を生成することです。たとえば、xmlDoc
がXMLの文字列への参照であると想定します。例4-8に示す方法を使用して、文字列をバイト配列に変換し、配列をByteArrwayInputStream
に変換してから解析できます。
例4-8 文字列内のXMLの変換
// create parser DOMParser parser=new DOMParser(); // create XML document in a string String xmlDoc = "<?xml version='1.0'?>"+ "<hello>"+ " <world/>"+ "</hello>"; // convert string to bytes to stream byte aByteArr [] = xmlDoc.getBytes(); ByteArrayInputStream bais = new ByteArrayInputStream(aByteArr,0,aByteArr.length); // parse and obtain DOM tree DOMParser.parse(bais); XMLDocument doc = parser.getDocument();
前述のコードで作成したXMLDocument
オブジェクトを再び文字列に変換するとします。このタスクは、PrintWriter
にStringWriter
をラップすることで実行できます。次の例に、この方法を示します。
StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); doc.print(pw); String YourDocInString = sw.toString();
$ORACLE_HOME/xdk/demo/java/parser/dom
にあるParseXMLFromString.java
は、XML文書を文字列として作成し、それを解析する完全なプログラムです。
入力XMLファイルに、é
などのアクセント付き文字が含まれているとします。例4-9に、アクセント付き文字を含むXML文書の解析方法の1つを示します。
例4-9 アクセント付き文字を含む文書の解析
DOMParser parser=new DOMParser(); parser.setPreserveWhitespace(true); parser.setErrorStream(System.err); parser.setValidationMode(false); parser.showWarnings(true); parser.parse (new FileInputStream(new File("file_with_accents.xml")));
XMLファイルを解析する場合、パーサーは、「UTF8エンコーディングが無効です。」例外をスローすることがあります。エンコーディングを明示的にUTF-8に設定した場合、またはエンコーディングを指定しない場合、パーサーはアクセント付き文字(127より大きいASCII値の文字)をUTF-8マルチバイト文字列の最初のバイトとして解析します。後続のバイトが有効なUTF-8文字列を構成していない場合、エラーが発生します。
このエラーは、XMLエディタがファイルをUTF-8エンコーディングを使用して保存していないことを意味します。たとえば、エディタはISO 8859-1エンコーディングを使用してファイルを保存している場合があります。エンコーディングはUnicodeの文字番号表現をディスクに書き込むために使用される特定のスキーマです。次の要素をXML文書の最上部に追加しても、エディタはファイルを表すバイトをUTF-8エンコーディングを使用してディスクに書き出しません。
<?xml version="1.0" encoding="UTF-8"?>
1つの解決策として、アクセント付き文字は、XML文書内でÙ
のように16進または10進フォーマットで表すと読み取ることができます。ただし、この方法を使用しない場合は、XMLファイルの作成時に使用したキャラクタ・セットに基づいてエンコーディングを設定できます。たとえば、使用しているツールまたはオペレーティング・システムに応じて、エンコーディングをISO-8859-1(Western European ASCII)またはそれ以外に設定してみてください。
&
、$
、#
などの特殊文字はタグ名として有効ではありません。たとえば、文書が会社名に基づいた名前をタグに付けていて、文書にタグ<A&B>
が含まれる場合、パーサーは無効な文字に関するエラーを発行します。
XML文書を最初から作成する場合は、有効なNameChars
のみを使用すると、この問題を回避できます。たとえば、タグに<A_B>、<AB>
、<A_AND_B>
などの名前を付けることができます。ただし、データベース表などの外部データ・ソースからXMLを生成する場合、XML 1.0はこの問題に対応していません。
データ型XMLType
は、DBMS_XMLGEN
パッケージでsetConvertSpecialChars
およびconvert
ファンクションを提供することで、この問題に対処しています。これらのファンクションを使用して、SQL名とXML名の特殊文字の使用を制御できます。SQLからXMLに名前をマップする機能によって、_XHHHH_
という形式(HHHH
は無効な文字のUnicode値)の無効なXML NameChar
文字がエスケープされます。たとえば、表名V$SESSION
はXMLの名前V_X0024_SESSION
にマップされます。
無効な文字のエスケープも、名前を他の場所に再ロードできるようにシリアライズする方法をユーザーに提供する有効な手段です。