12 XML Parsing for Java

Extensible Markup Language (XML) parsing for Javaについて説明します。

12.1 XML Parsing for Javaの概要

XML parsing for Javaについて説明します。

12.1.1 Javaを使用した解析の前提条件

Oracle XML ParserはXML文書を読み取り、Document Object Model (DOM)アプリケーション・プログラミング・インタフェース(API)またはSimple API for XML (SAX)を使用してそのコンテンツと構造にアクセスします。解析は検証モードまたは非検証モードで行えます。

この章では、次のテクノロジを十分に理解していると想定します。

  • Document Object Model (DOM): XML文書の構造を示すメモリー内ツリー表現です。

  • Simple API for XML (SAX): イベントベースのXML解析の標準です。

  • Java API for XML Processing (JAXP): JavaアプリケーションでXMLを処理するための標準インタフェースで、DOM標準とSAX標準をサポートします。

  • Document Type Definition (DTD): XML文書の有効な構造を定義する一連のルールです。

  • XML Schema: XML文書の有効なデータ型の構造を定義するWorld Wide Web Consortium (W3C)勧告です。

  • <a href="glossary.html#GUID-55AB1901-F16B-4FBD-9C2B-7164C71662B0" title='Related element names or attributes within an XML document. Namespace syntax and usage are defined by a W3C recommendation. For example, element XML名前空間: XML文書内の要素名や属性名を区別するためのメカニズムです。

  • バイナリXML: コンパクトなスキーマを認識した形式を使用するXML表現。拡張性のあるDOMも拡張性のないDOMも、この形式でXML文書を保存できます。

詳細は、「関連ドキュメント」のXMLの資料のリストを参照してください。

12.1.2 XML Parsing for Javaの標準および仕様

DOMレベル1、レベル2およびレベル3の仕様はW3C勧告です。

W3CのDOM仕様については、Document Object Model (DOM) Technical Reportsを参照してください。

SAXにはバージョン1.0(非推奨)と2.0があります。SAXはW3C仕様ではありません。SAXプロジェクトを参照してください。

XML名前空間はW3C勧告です。Namespaces in XML 1.0 (Third Edition)を参照してください。

JCR 1.0(JSR 170とも呼ばれます)は、アプリケーションがコンテンツ・リポジトリと対話するための標準Java APIを定義しています。JSR 170: Content Repository for Java technology APIを参照してください。

JAXPは、プロセッサの実装に関係なくDOM、SAX、XML SchemaおよびExtensible Stylesheet Language Transformation (XSLT)を使用可能にする標準APIです。JAXP仕様およびその他の情報は、OTNのJavaを参照してください。

関連項目:

Oracle XML Developer's Kit (XDK)でサポートする標準の詳細は、「Oracle XML Developer's Kit標準」を参照してください

12.1.3 巨大ノードの処理

XMLノードへのDOMストリーム・アクセスはProcedural Language/Structured Query Language (PL/SQL)およびJava APIによって行われます。XML文書内のノードは64KBを大幅に超えることができるようになりました。したがって、Joint Photographic Experts Group (JPEG)、Word、PDF、リッチ・テキスト形式(RTF)およびHTML文書を問題なく格納できます。

関連項目:

Javaの巨大ノードに関する機能の詳細は、『Oracle XML DB開発者ガイド』を参照してください

12.1.4 JavaでのXML解析: 概要

XMLParserは、XML Parser for Javaの抽象ベース・クラスです。インスタンス化されたパーサーは、parse()メソッドを起動してXML文書を読み取ります。XMLDOMImplementationファクトリ・メソッドは、バイナリXMLを解析し、拡張性のあるDOMを作成する別の方法を提供します。

図12-1に、XMLParserを使用した解析の基本プロセスを示します。図はXMLDOMImplementation()には適用されません。

図12-1 XML Parserのプロセス

図12-1の説明が続きます
「図12-1 XML Parserのプロセス」の説明

Javaアプリケーションでは、次のAPIを使用して、解析済XML文書にアクセスできます。

  • DOM API

    DOM APIは、XML文書を解析し、メモリー内に文書のツリー表現を構築します。DOM APIを使用して解析するには、DOMParserオブジェクトまたはXMLDOMImplementationインタフェース・ファクトリ・メソッドを使用してプラガブルで拡張性のあるDOM (SDOM)を作成します。

  • SAX API

    SAX APIは、XML文書をイベントのストリームとして処理します。したがって、プログラムから文書内のランダムな位置へのアクセスはできません。SAX APIを使用して解析するには、SAXParserオブジェクトを使用します。

  • JAXP

    JAXPは、DOM、SAXおよびExtensible Stylesheet Language (XSL)をサポートするJava固有のAPIです。JAXPを使用して解析するには、DocumentBuilderまたはSAXParserオブジェクトを使用します。

後続のトピックでは、例12-1のサンプルXML文書を使用して、DOM、SAX、JAXPの違いを示します。

例12-1 サンプルXML文書

<?xml version="1.0"?>
  <EMPLIST>
    <EMP>
     <ENAME>MARY</ENAME>
    </EMP>
    <EMP>
     <ENAME>SCOTT</ENAME>
    </EMP>
  </EMPLIST>

12.1.5 XML解析でのDOM

DOM APIは、XML文書のインメモリー・ツリー表現を構築します。DOM APIは、ツリーをナビゲートおよび処理するためのクラスおよびメソッドを提供します。

たとえば、例12-1に示した文書の場合、DOM APIは図12-2に示すインメモリー・ツリーを作成します。

DOM APIについて重要な点は次のとおりです。

  • DOM APIでは、オブジェクトがよく知られたツリー構造で提供されるため、SAX APIよりも簡単に使用できます。

  • ツリーは操作可能です。たとえば、要素を並べ替えたり、名前を変更できます。また、要素、属性とも追加および削除できます。

  • 対話型アプリケーションでメモリー内にツリーを格納できるため、ユーザーがツリーにアクセスして操作できます。

  • XDKには、XPathをサポートするDOM API拡張が含まれています。(DOM標準ではXPathをサポートしませんが、ほとんどのXPath実装でDOMが使用されます。)

  • XDKではSDOMがサポートされます。詳細は、「SDOM」を参照してください。

12.1.5.1 DOM作成

XDK for Javaでは、3つの方法で、つまり、DOMParserを使用して文書を解析をするか、XMLDOMImplementationファクトリ・メソッドを使用(拡張性のあるDOMを作成)するか、または(一般的ではありませんが)XMLDocumentコンストラクタを使用してDOMを作成できます。

12.1.6 SDOM

XDKではプラガブルで拡張性のあるDOM (SDOM)がサポートされます。このサポートにより、メモリーの非効率、限定的なスケーラビリティ、DOM構成の制御不足という問題が緩和されます。SDOMの作成および構成は主にXMLDOMImplementationクラスを使用してサポートされます。

SDOMについて重要な点は次のとおりです。

  • SDOMでは、既存の形式のプラグイン外部XMLを使用できます。

    プラグインXMLデータは、バイナリXML、XMLTypeおよびサード・パーティ製のDOMなど様々な形式が可能です。SDOMは外部XMLを内部表現にレプリケートする必要がありません。SDOMは、ReaderおよびInfosetWriter抽象インタフェースを介してプラグインXMLデータの上位で作成されます。

  • SDOMは一時ノードを持ちます。

    ノードはアクセスされる場合にのみ作成され、使用されない場合は解放されます。

  • SDOMは、入力および出力ともにバイナリXMLを使用できます。

    SDOMは、次の2つの方法でデータと対話します。

    • 抽象InfosetReaderおよびInfosetWriterインタフェースを介して対話。

      BinXMLデータの読取りおよび書込みを行う場合、ユーザーはInfosetReaderおよびInfosetWriterBinXML実装を使用できます。他の形式のXML infosetの読取りおよび書込みを行う場合、ユーザーは独自の実装を使用できます。

    • BinXMLStreamに対するInfosetReaderおよびInfosetWriterアダプタの実装を介して対話。

12.1.6.1 プラガブルなDOMサポート

プラガブルなDOMでは、データ・レイヤーからDOM APIを分割できます。DOM APIは、InfosetReaderおよびInfosetWriterインタフェースによってデータから分離されます。プラガブルなDOMを使用すると、1つのプロセッサから別のプロセッサへのXMLデータの移動が容易になります。

DOM APIには、データの上位に統合された標準APIが含まれており、ノード・アクセス、ナビゲーション、更新プロセスおよび検索機能がサポートされています。

関連項目

12.1.6.2 遅延マテリアライズ

遅延マテリアライズを使用すると、XDKはアクセスするノードのみを作成し、使用しないノードをメモリーから解放します。スケーラビリティが向上するため、非常に大きなXML文書も処理可能です。

12.1.6.3 構成可能なDOM設定

DOM構成は他のアプリケーションに適合するように構成されています。DOMの構成には、読取り専用、ストリーム、一時更新およびシャドウ・コピーなど様々なアクセス・パターンを使用して、最大限のメモリーを使用および実行可能にできます。

12.1.6.4 Fast InfosetのDOMサポート

Oracleで開発されたFast Infosetは、XML Infosetを表現するコンパクトなバイナリXML形式です。この形式は、国際標準ITU-T SG 17およびISO/IEC JTC1 SC6になっています。XML InfosetのFast Infoset表現は、Java XMLおよびWebサービス・コミュニティ内で一般的になっています。

Fast Infosetには、他の形式と比較して次のような利点があります。

  • XMLテキストと比較してよりコンパクトで、より高速な解析、より適切な直列化が可能です。

  • XMLテキストの解析よりも高速なエンコードおよびデコードが可能で、Fast Infosetドキュメントは一般に、対応するXMLテキストよりも20から60%小さくなります。

  • 他のバイナリXML形式よりもパフォーマンスと圧縮率に勝っており、小規模ドキュメントから大規模ドキュメントまでバランスよく処理できます。

SDOMは、拡張性をサポートするXDK DOM構成です。直列化されたバイナリ・データの最上位に構築され、XPathやXSLTなどのアプリケーションにDOM APIを提供します。SDOMには、抽象的なAPI InfosetReaderを介してバイナリ・データを読み込む、オープンなプラグイン・アーキテクチャがあります。InfosetReader APIにより、SDOMは転送されるバイナリ・データをデコードし、ノードの開始場所を記憶し、デコードする場所を検索できます。このサポートにより、SDOMは使用されていないノードを解放し、必要なときにこれらのノードをバイナリ・データから再作成できます。バイナリ・データをファイルやBLOBなどの外部に保存すると、SDOMの拡張性が高まります。

12.1.7 XML ParserでのSAX

DOMとは異なりSAXはイベントベースであるため、SAX APIは入力文書のインメモリー・ツリー表現を構築しません。SAX APIは、要素単位で入力文書を処理し、イベントと重要なデータをアプリケーションのコールバック・メソッドに報告できます。

たとえば、例12-1に示した文書の場合、SAX APIは、文書を図12-2に示す一連のリニアなイベントとして解析します。

SAX APIについて重要な点は次のとおりです。

  • XMLツリーの操作が必要でない検索操作やその他のプログラムに有用です。

  • メモリー・リソースを大量に消費しません。

  • データベースからXML文書を取得する場合は、DOMよりも高速です。

図12-2 DOM(ツリーベース)APIとSAX(イベントベース)APIの比較

図12-2の説明が続きます
「図12-2 DOM(ツリーベース)APIとSAX(イベントベース)APIの比較」の説明

12.1.8 XML ParserでのJAXP

JAXPを使用すると、SAXまたはDOMパーサーの実装をプラグインできます。XDKで提供されているSAX APIとDOM APIは、JAXPがサポートするベンダー固有実装の例です。JAXPの主な利点は、相互運用可能なアプリケーションを作成できることです。

JAXPを介して使用可能な機能を使用するアプリケーションでは、非常に簡単に実装を切り替えることができます。

JAXPの主な短所は、ベンダー固有のAPIよりも実行速度が遅いことです。また、JAXPには、Oracle固有のAPIが提供するいくつかの機能がありません。一部のOracle固有の機能はJAXP拡張メカニズムを介して使用できますが、これらの拡張を使用するアプリケーションは実装の切替えという柔軟性を失います。

12.1.9 XML Parserでの名前空間のサポート

名前空間は、XML文書内にある要素または属性間の名前の競合を回避するために役立ちます。

例12-2は、会社の住所と従業員の住所の両方に<address>タグを使用するXML文書です。XMLプロセッサは、会社の住所と従業員の住所を区別できません。

例12-3は、次の名前空間を使用して会社と従業員の<address>タグを区別するXML文書です。

http://www.oracle.com/employee
http://www.oracle.com/company

例12-3では、com接頭辞を最初の名前空間に関連付け、emp接頭辞を2番目の名前空間に関連付けています。

名前空間を使用した文書を解析する場合、次の用語を覚えておくと有用です。

  • 名前空間URIは、xmlnsに割り当てられるURIです。例12-3では、http://www.oracle.com/employeeおよびhttp://www.oracle.com/companyが名前空間URIです。

  • 名前空間の接頭辞は、xmlnsで宣言された名前空間の識別子です。例12-3では、empおよびcomが名前空間の接頭辞です。

  • ローカル名は、名前空間の接頭辞が付いていない要素または属性の名前です。例12-3では、employeeおよびcompanyがローカル名です。

  • 修飾名は、ローカル名に接頭辞を加えたものです。例12-3では、emp:employeeおよびcom:companyが修飾名です。

  • 拡張名は、名前空間の接頭辞を名前空間URIで置換した結果です。例12-3では、http://www.oracle.com/employee:employeeおよびhttp://www.oracle.com/company:companyが拡張要素名です。

例12-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>

例12-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>

12.1.10 XML Parserでの検証

XML文書を解析するには、parse()メソッドを起動します。通常、parse()メソッドに伴って初期化メソッドおよび終了メソッドを起動します。

解析モードは検証または非検証のいずれかです。検証モードでは、解析によって文書が指定されたDTDまたはXMLスキーマに準拠しているかどうかが確認されます。非検証モードでは、パーサーは整形式であるかどうかのみ確認します。解析モードを設定するには、oracle.xml.parser.v2.XMLParserに定義されているsetValidationMode()メソッドを起動します。

表12-1に、XDKパーサーで使用できるsetValidationMode()のフラグを示します。

表12-1 XML Parser for Javaの検証モード

名前 XML Parserによる処理 . . .

非検証モード

NONVALIDATING

XMLが整形式であることを確認し、データを解析します。

DTD検証モード

DTD_VALIDATION

XMLが整形式であることを確認し、XMLデータがDTDに対して妥当であるかどうかを検証します。<!DOCTYPE>宣言で定義されたDTDは、入力XML文書の位置に相対的である必要があります。

スキーマ検証モード

SCHEMA_VALIDATION

XML文書を、その文書に対して指定されたXMLスキーマに従って検証します。

LAX検証モード

SCHEMA_LAX_VALIDATION

スキーマ定義が検出されない場合、インスタンス・ドキュメントの一部またはすべての検証を試行します。定義が検出されない場合も、エラーは発生しません。schemaディレクトリのサンプル・プログラムXSDLax.javaを参照してください。

厳密な検証モード

SCHEMA_STRICT_VALIDATION

インスタンス・ドキュメント全体の検証を試行します。スキーマ定義が検出されない場合またはインスタンスが定義に準拠しない場合は、エラーが発生します。

部分検証モード

PARTIAL_VALIDATION

DTD(存在する場合)に従って、入力XML文書のすべてまたは一部を検証します。DTDが存在しない場合、パーサーは非検証モードに設定されます。

自動検証モード

AUTO_VALIDATION

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()とは異なり、検証モードを変更しません。

関連項目:

12.1.11 XML Parserでの圧縮

XML Parserに実装されているXML Compressorを使用して、XML文書を圧縮および解凍できます。圧縮アルゴリズムは、XMLタグのトークン化に基づいています。

これは、すべてのXML文書にはタグの繰返しがあるため、それらのタグをトークン化すると、データが大幅に圧縮されることを前提としています。圧縮の程度は、文書のタイプに依存します。タグの数が多く、テキスト・コンテンツが少ないほど、圧縮率が向上します。

Oracle XML Parserは、XML文書から生成されたインメモリーDOMツリーまたはSAXイベントから、圧縮したバイナリ出力を生成します。表12-2に、2種類の圧縮を示します。

表12-2 DOMとSAXでのXML圧縮

タイプ 説明 圧縮API

DOMベース

目的は、DOMツリーの構造情報および階層情報を失うことなく、XML文書のサイズを小さくすることです。パーサーでは、解析済XML文書に対応するインメモリーDOMツリーがシリアライズされ、圧縮したXML出力ストリームが生成されます。シリアライズされたストリームは、再度読み取られると、DOMツリーを再生成します。

writeExternal()メソッドを使用して、圧縮したXMLを生成し、readExternal()メソッドを使用して、そのXMLを再構築します。これらのメソッドはoracle.xml.parser.v2.XMLDocumentクラス内にあります。

SAXベース

SAXパーサーでは、XMLファイルを解析する際に圧縮したストリームが生成されます。SAXパーサーによって生成されたSAXイベントは、SAX圧縮ユーティリティによって処理されます。SAX圧縮ユーティリティは、圧縮したバイナリ・ストリームを生成します。

圧縮したXMLを生成するには、出力ストリームをコンストラクタに渡すことにより、oracle.xml.comp.CXMLHandlerBaseをインスタンス化します。オブジェクトをSAXParser.setContentHandler()に渡してから、parse()メソッドを実行します。XMLを解凍するにはoracle.xml.comp.CXMLParserクラスを使用します。

注意: CXMLHandlerBaseはSAX 1.0と2.0の両方を実装しますが、1.0は非推奨のため、2.0 APIを使用することをお薦めします。

DOMおよびSAXから生成された圧縮ストリームには互換性があるため、SAXから生成された圧縮ストリームを使用してDOMツリーを生成したり、その逆を行えます。通常、XML文書と同様に、圧縮したXMLデータ出力はデータベースにBLOBデータ・アイテムとして格納できます。

プログラムで大きなXML文書を解析し、メモリー内にDOMツリーを作成すると、パフォーマンスに影響する場合があります。DOMツリーをシリアライズすることにより、XML文書をバイナリ・ストリームに圧縮できます。圧縮したストリーム内のXMLデータを検証せずに、DOMツリーを再生成できます。圧縮したストリームはシリアライズされたストリームとして処理できますが、ストリーム内のデータは、Javaのデフォルトのシリアライズによって実装される圧縮よりも厳密に制御および管理されます。

注意:

Oracle Textは、圧縮されたXML文書を検索できません。解凍によりパフォーマンスが低下します。クライアントとサーバーの間でファイルを転送する場合、Hypertext Transfer Protocol (HTTP)圧縮が簡単です。

12.2 XML Parsing for Javaの使用: 概要

XML開発の基本コンポーネントはXML Parsingです。XML Parsing for JavaはスタンドアロンのXMLコンポーネントであり、プログラムで処理できるように、XML文書(場合によってはスタンドアロンのDTDまたはXMLスキーマも)を解析します。

注意:

サポートされている任意のJava仮想マシン(JVM)のパーサーを使用できます。Oracle 9i以降では、パーサーをデータベースにロードし、内部Oracle JVMを使用できます。その他のデータベース・バージョンでは、外部JVM内でパーサーを実行し、JDBCを介してデータベースに接続します。

12.2.1 XML Parser for Javaの使用: 基本プロセス

XML Parser for Javaの使用の基本プロセスについて説明します。

図12-3に、標準的なXML処理アプリケーションでXMLパーサーを使用する方法を示します。

図12-3 XML Parser for Java

図12-3の説明が続きます
「図12-3 XML Parser for Java」の説明

図12-3に示したアプリケーションの基本プロセスは次のとおりです。

  1. DOMまたはSAXパーサーにより、入力XML文書が解析されます。たとえば、プログラムはXMLデータ文書、DTD、XMLスキーマおよびXSLスタイルシートを解析できます。

  2. 検証パーサーを実装すると、プロセッサは、提供されているDTDまたはXMLスキーマに対してXMLデータ文書が妥当であるかどうかの検証を試行します。

関連項目:

XMLパーサーのクラスとメソッドについては、Oracle Database XML Java APIリファレンスを参照してください

12.2.2 XML Parser for Javaのデモ・プログラムの実行

XML Parser for Javaのデモ・プログラムは、$ORACLE_HOME/xdk/demo/java/parserにあります。

表12-3に、デモ・プログラムが格納されているサブディレクトリを示します。

表12-3 Javaパーサーのデモ

ディレクトリ 内容 プログラムの説明 . . .

common

class.xml
DemoUtil.java
empl.xml
family.dtd
family.xml
iden.xsl
NSExample.xml
traversal.xml

XMLパーサーで一般的に使用するXMLファイルおよびJavaプログラムです。たとえば、XSLTスタイルシートiden.xslを使用して、XMLファイルの識別情報変換を実行できます。DemoUtil.javaは、ファイル名からURLを作成するためのヘルパー・メソッドを実装し、他の多くのデモ・プログラムで使用されます。

comp

DOMCompression.java
DOMDeCompression.java
SAXCompression.java
SAXDeCompression.java
SampleSAXHandler.java
sample.xml
xml.ser

次のようなDOMおよびSAX圧縮が示されます。

  • DOMCompression.javaでは、DOMツリーが圧縮されます。

  • DOMDeCompression.javaでは、圧縮したストリームからDOMが再度読み取られます。

  • SAXCompression.javaでは、SAXパーサーからの出力が圧縮されます。

  • SAXDeCompression.javaでは、圧縮したストリームからSAXイベントが再生成されます。

  • SampleSAXHandler.javaでは、SAX DeCompressorからスローされたイベントを処理するハンドラの使用方法が示されます。

dom

AutoDetectEncoding.java
DOM2Namespace.java
DOMNamespace.java
DOMRangeSample.java
DOMSample.java
EventSample.java
I18nSafeXMLFileWritingSample.java
NodeIteratorSample.java
ParseXMLFromString.java
TreeWalkerSample.java

次のようなDOM APIの使用方法が示されます。

  • DOM2Namespace.javaでは、DOMレベル2.0 APIの使用方法が示されます。

  • DOMNamespace.javaでは、DOM APIへの名前空間による拡張の使用方法が示されます。

  • DOMRangeSample.javaでは、DOM範囲APIの使用方法が示されます。

  • DOMSample.javaでは、DOM APIの基本的な使用方法が示されます。

  • EventSample.javaでは、DOM Event APIの使用方法が示されます。

  • NodeIteratorSample.javaでは、DOM Iterator APIの使用方法が示されます。

  • TreeWalkerSample.javaでは、DOM TreeWalker APIの使用方法が示されます。

jaxp

JAXPExamples.java
age.xsl
general.xml
jaxpone.xml
jaxpone.xsl
jaxpthree.xsl
jaxptwo.xsl
oraContentHandler.java

JAXPの様々な使用方法が示されます。

  • JAXPExamples.javaでは、JAXP 1.1 APIを使用してOracleエンジンを実行する方法の例がいくつか示されます。

  • oraContentHandler.javaでは、SAXコンテンツ・ハンドラが実装されます。このプログラムは、XMLタグを認識する際に、startDocument()endDocument()startElement()endElement()などのメソッドを起動します。

sax

SAX2Namespace.java
SAXNamespace.java
SAXSample.java
Tokenizer.java

SAX APIの様々な使用方法が示されます。

  • SAX2Namespace.javaでは、SAX 2.0の使用方法が示されます。

  • SAXNamespace.javaでは、SAX APIへの名前空間による拡張の使用方法が示されます。

  • SAXSample.javaでは、SAX APIの基本的な使用方法が示されます。

  • Tokenizer.javaでは、XMLTokenインタフェースAPIの使用方法が示されます。このプログラムは、XMLTokenインタフェースを実装します。このインタフェースは、setTokenHandler()メソッドを使用して登録する必要があります。XMLTokenのリクエストは、setToken()メソッドを使用して登録します。トークン化実行中、パーサーは、ドキュメントを検証せず、内部および外部のユーティリティの追加または読取りも行いません。

xslt

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を使用した文書の変換が示されます。

  • XSLSample.javaでは、Oracle XML ParserのXSL処理機能の使用方法が示されます。指定された入力スタイルシートを使用して入力XML文書が変換されます。このデモは、XSL変換の結果をDocumentFragmentとして構築するため、xsl:output機能をサポートしません。

  • XSLSample2.javaでは、与えられた入力スタイルシートを使用して入力XML文書が変換されます。このデモは、XSL変換の結果をストリーム化するため、xsl:output機能をサポートします。

関連項目: 「XSLT Processorのデモ・プログラムの実行」

サンプル・プログラムのコンパイルおよび実行方法に関するドキュメントは、READMEファイルにあります。基本的な手順は次のとおりです。

  1. ディレクトリを$ORACLE_HOME/xdk/demo/java/parserディレクトリ(UNIXの場合)または%ORACLE_HOME%\xdk\demo\java\parserディレクトリ(Windowsの場合)に変更します。
  2. 「XDK for Java環境の設定」の説明に従って、環境を設定します。
  3. 次の各サブディレクトリに移動し、コマンドラインで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という拡張子の付いたファイルに書き込まれます。

  4. *.outファイルを表示して、プログラムの出力を参照できます。

12.2.3 Java XML Parserコマンドライン・ユーティリティ(oraxml)の使用

$ORACLE_HOME/bin (UNIXの場合)または%ORACLE_HOME%\bin (Windowsの場合) にあるoraxmlユーティリティは、XML文書を解析するコマンドライン・インタフェースです。XML文書が整形式であるか、および妥当であるかを確認します。

oraxmlを使用する場合、次の点を確認してください。

  • XDK for Java環境の設定の説明に従ってCLASSPATHを設定し、CLASSPATH環境変数がxmlparserv2.jarファイルを参照しています。

  • PATH環境変数で、使用するバージョンのJava Development Kit (JDK)のJavaインタプリタを見つけることができます。

表12-4に、oraxmlのコマンドライン・オプションを示します。

表12-4 oraxmlのコマンドライン・オプション

オプション 用途

-help

ヘルプ・メッセージを出力します。

-version

バージョン番号の出力

-novalidate fileName

入力ファイルが整形式かどうかの確認

-dtd fileName

DTD検証を使用した入力ファイルの検証

-schema fileName

スキーマ検証を使用した入力ファイルの検証

-log logfile

出力ログ・ファイルへのエラーの書込み

-comp fileName

入力XMLファイルの圧縮

-decomp fileName

入力圧縮ファイルの解凍

-enc fileName

入力ファイルのエンコーディングの出力

-warning

警告の表示

たとえば、$ORACLE_HOME/xdk/demo/java/parser/commonディレクトリに変更します。コマンドラインで次のコマンドを実行することにより、文書family.xmlfamily.dtdに対して妥当であるかどうかを検証できます。

oraxml -dtd -enc family.xml

出力は次のとおりです。

The encoding of the input file: UTF-8

The input XML file is parsed without errors using DTD validation mode.

12.3 DOMを使用したXMLの解析

W3C標準ライブラリorg.w3c.domでは、Documentクラスと、DOMのコンポーネント用のクラスが定義されています。Oracle XML Parserには、標準のDOM APIが組み込まれており、W3C DOMの勧告に準拠しています。

org.w3c.domとともに、Oracle XML Parsingには、DOM APIを実装するクラスが組み込まれており、これらを拡張して文書フラグメントの出力や名前空間情報の取得などの機能を提供しています。

12.3.1 DOM API for Javaの使用

XMLアプリケーションにDOMベースのコンポーネントを実装するために使用できるJavaクラスについて説明します。

次のクラスを使用します。

  • oracle.xml.parser.v2.DOMParser

    このクラスは、W3C勧告に準拠したXML 1.0のパーサーを実装します。DOMParserXMLParserを拡張するため、XMLParserのすべてのメソッドはDOMParserで使用できます。

  • oracle.xml.parser.v2.XMLDOMImplementation

    このクラスにはSDOMの作成に使用されるファクトリ・メソッドが含まれます。

DOMNamespaceおよびDOM2Namespaceクラスも利用できます。これらのクラスは、$ORACLE_HOME/xdk/demo/java/parser/domに含まれているサンプル・プログラムです。

12.3.2 DOMパーサーのアーキテクチャ

DOMパーサーのアーキテクチャについて説明します。

図12-4 DOMパーサーの基本アーキテクチャ

図12-4の説明が続きます
「図12-4 DOMパーサーの基本アーキテクチャ」の説明

12.3.3 基本的なDOM解析の実行

DOMSample.javaには、入力XML文書の解析およびDOMを介したアクセスの基本ステップが示されています。DOMSample.javaは、入力としてXMLファイルを受け取って解析し、DOMツリー内の要素と属性を出力します。

ステップは次のとおりです。このステップで、使用可能なメソッドおよびインタフェースを示します。

  1. DOMParser()コンストラクタを起動してDOMParserオブジェクト(パーサー)を作成します。

    DOMSample.java内のコードは次のとおりです。

    DOMParser parser = new DOMParser();
    
  2. 表12-5のメソッドを使用してパーサーのプロパティを構成します。

    DOMSample.javaの次のコード部分は、エラー出力ストリームを指定し、検証モードをDTD検証に設定して、警告メッセージを有効にします。

    parser.setErrorStream(System.err);
    parser.setValidationMode(DOMParser.DTD_VALIDATION);
    parser.showWarnings(true);
    
  3. 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]);
             ...
    
  4. getDocument()を起動して、パーサーがインメモリーDOMツリーのルートへのハンドルを取得します。このハンドルはXMLDocumentオブジェクトです。

    このハンドルを使用して、解析されたXML文書のすべての部分にアクセスできます。XMLDocumentクラスは、表12-6のインタフェースを実装します。

    DOMSample.javaのコード部分は次のとおりです。

    XMLDocument doc = parser.getDocument();
    
  5. 表12-7XMLDocumentメソッドを起動し、取得した文書のDOMノードを取得および操作します。

    DOMSample.javaの次のコード部分は、DOMParser.print()メソッドを使用して、DOMツリーの要素および属性を出力します。

    System.out.print("The elements are: ");
    printElements(doc);
     
    System.out.println("The attributes of each element are: ");
    printElementAttributes(doc);
    

    DOMSample.javaの次のコード部分は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();
    }
    

    DOMSample.javaの次のコード部分は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();
       }
    }
    
  6. reset()メソッドを起動することにより、パーサーの状態をリセットします。これで、パーサーが新規文書を解析する準備ができます。

表12-5に、DOMParserの構成メソッドの概要を示します。

表12-5 DOMParser構成メソッド

メソッド 用途

setBaseURL()

外部エンティティとDTDをロードするためのベースURLを設定します。XML文書がInputStreamの場合、このメソッドを起動します。

setDoctype()

解析時に使用するDTDを指定します。

setErrorStream()

エラーと警告の出力の出力ストリームを作成します。

setPreserveWhitespace()

入力XML文書内の空白を保持するようにパーサーに指示します。

setValidationMode()

パーサーの検証モードを設定します。表12-1に、このメソッドで使用できるフラグを示します。

showWarnings()

パーサーが警告を出力するかどうかを指定します。

表12-6に、XMLDocumentクラスが実装するインタフェースの概要を示します。

表12-6 XMLDocumentにより実装されるいくつかのインタフェース

インタフェース インタフェースによって定義されるもの

org.w3c.dom.Node

文書ツリー内の単一ノードと、ノードをアクセスおよび処理するためのメソッド。

org.w3c.dom.Document

XML文書全体を表すNode

org.w3c.dom.Element

XML要素を表すNode

表12-7に、DOMのツリー・ノードの取得および操作のためのメソッドの概要を示します。

表12-7 DOMツリー・ノードの取得および操作のためのメソッド

メソッド 用途

getAttributes()

このノードが要素である場合はその属性を含むNamedNodeMapを生成し、要素でない場合はnullを生成します。

getElementsbyTagName()

特定のレベルの特定のタグ名と一致するすべての要素を再帰的に取得します。このメソッドでは、任意のタグと一致する*タグがサポートされます。文書のルートへのハンドルを通じてgetElementsByTagName("*")を起動して、文書内のすべての要素のリストを生成します。

getExpandedName()

要素の拡張名を取得します。このメソッドは、NSNameインタフェースで指定されます。

getLocalName()

この要素のローカル名を取得します。要素名が<E1:locn xmlns:E1="http://www.oracle.com/"/>の場合は、locnがローカル名です。

getNamespaceURI()

このノードの名前空間URIを取得するか、名前空間URIが指定されていない場合はnullを戻します。要素名が<E1:locn xmlns:E1="http://www.oracle.com/"/>の場合は、http://www.oracle.comが名前空間URIです。

getNodeName()

DOMツリーのノードの名前を取得します。

getNodeValue()

タイプに応じて、このノードの値を取得します。このノードはNodeインタフェース内にあります。

getPrefix()

要素の名前空間の接頭辞を取得します。

getQualifiedName()

要素の修飾名を取得します。要素名が<E1:locn xmlns:E1="http://www.oracle.com/"/>の場合は、E1:locnが修飾名です。

getTagName()

DOMツリー内の要素の名前を取得します。

12.3.4 SDOMの作成

プラガブルで拡張性のあるDOM (SDOM)の作成方法および使用方法について説明します。

12.3.4.1 SDOMの使用

SDOMの使用方法について説明します。

SDOMは、データとは別にDOM APIを持ちます。基礎となるデータは、内部データまたはプラグイン・データのいずれかで、いずれの場合もバイナリXML形式を使用できます。

内部データは、解析されていないXMLテキストです。プラグインするには、内部データをバイナリXMLとして保存し、DOMParserによって解析する必要があります。解析済バイナリXMLは、DOM APIレイヤーのInfoSetReaderにプラグインされます。InfosetReader引数は、基礎となるXMLデータへのインタフェースです。

プラグイン・データは、解析済で、プロセッサ間で転送可能なXMLテキストです。

SDOMを作成するには、XMLDOMImplementationオブジェクトでInfosetReader APIを介してXMLデータをプラグ・インします。次に例を示します。

public Document createDocument(InfosetReader reader) throws DOMException

InfosetReaderAPIはBinXMLStreamの上位に実装されます。XMLデータの他の形式のオプションのアダプタ(dom4j、JDOM、Java Database Connectivity (JDBC)など)もサポートされます。独自の実装もプラグインできます。

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();
     }
}
12.3.4.1.1 InfosetReaderオプション

InfosetReader APIでサポートされるオプションを示します。

サポートされる操作は次のとおりです。

  • コピー(オプションですが、BinXMLStreamInfosetReaderでは常にサポートされます)

    文書間のDOMのシャドウ・コピーをサポートするには、Cloneメソッドを使用してInfosetReaderの新規コピーを作成し、スレッドを安全にします。詳細は、「シャドウ・コピーの使用」を参照してください。

  • フォーカスの移動(オプション)

    遅延マテリアライズをサポートするために、InfosetReaderは、offsetによって指定されたどの場所にもフォーカスを移動できます。

    If (reader.hasSeekSupport())
       reader.seek(offset);
    

    詳細は、「遅延マテリアライズの使用」を参照してください

12.3.4.1.2 InfosetWriter

InfosetWriterは、データの書込みをサポートするInfosetReader APIの拡張です。XDKでは、バイナリXMLの上位でInfosetWriterが実装されます。この実装は変更できません。

12.3.4.1.3 XMLテキストのバイナリXMLとしての保存

XMLテキストから拡張性のあるDOMを作成するには、DOMParserの実行前に、XMLテキストをバイナリXMLまたはバイナリXMLへの参照として保存する必要があります。XMLテキストをバイナリXMLとして保存するには、doc.save引数をfalseに設定します。

XMLDocument doc;
InfosetWriter writer;
doc.save(writer, false);
writer.close();

データ・ソースがデシリアライズに使用可能と判明している場合は、doc.save引数をtrueに設定して実際のデータのかわりにバイナリXMLのセクション参照を保存できます。

12.3.4.2 遅延マテリアライズの使用

遅延マテリアライズを使用して、空のDOMをプラグインできます。それにより、必要な場合はデータを取り出せ、不要になったらノードを解放(参照解除)できます。SDOMは、手動ノード参照解除も自動ノード参照解除もサポートします。

12.3.4.2.1 オンデマンドでのデータの取出し

プラグインDOMアーキテクチャは、ツリーのルートとして単一のDocumentノードを含む空のDOMを作成します。残りのDOMツリーは、後でアクセスして拡張できます。

ノードは、拡張されない子ノードおよび兄弟関係のノードを持つことができますが、親および祖先は常に拡張されます。DOMは追加データを取り出して次のノードを作成できるように、各ノードは次のノードのInfoSetReader.Offsetプロパティを保持します。

アクセス方法のタイプによっては、DOMノードは戻されたノードのセット以上に拡張することもできます。

アクセス方法 説明

DOMナビゲーション

最初の子や、最後の子、親、前後の兄弟関係などの近隣のノードへのアクセスを可能にします。ノードの作成が必要な場合は、ドキュメント内の順に行われます。

識別子(ID)索引付け

DTDまたはXMLスキーマは、型IDでノードを指定できます。DOMがIDの索引付けをサポートする場合、それらのノードは、索引を使用して直接取出し可能になります。拡張性のあるDOMでは、索引による取得で、前のすべてのノードが拡張されるわけではありませんが、祖先のノードは生成されます。

XPath式

XPath評価により、メモリー内のすべての中間ノードが生成されます。たとえば、子孫の軸「//」により全体のサブツリーが拡張されますが、評価後に解放されるものもあります。

12.3.4.2.2 自動ノード参照解除の使用

DOMナビゲーション・サポートでは、ノード間に追加リンクが必要です。自動参照解除モードでは、ガベージ・コレクション時に弱いリンクが自動的に参照解除されます。自動ノード参照解除を使用するには、PARTIAL_DOM属性をBoolean.TRUEに設定します。

リンクの重要性に基づいてノードが解放されます。親ノードへのリンクは削除されません。祖先が有効範囲内の名前空間のコンテキストを提供し、InfosetReaderなどのストリームAPIを使用して削除済の親ノードを取得するのは難しいためです。

SDOMツリーでは、親および前の兄弟関係ノードへのリンクは強く、子および次の兄弟関係ノードへのリンクは弱いです。JVMがノードを解放しても、それらへの参照は基礎となるデータで使用可能であるため、必要な場合は再作成できます。

12.3.4.2.3 手動ノード参照解除の使用

手動ノード参照解除について説明します。

手動参照解除モードでは、弱参照はありません。アプリケーションは、DOMツリーから文書フラグメントを明示的に参照解除します。アプリケーションが確定的な順序でデータを処理する場合、ノードの解放と再作成を繰り返し行う余分なオーバーヘッドは回避することをお薦めします。

手動ノード参照解除を使用するには、属性PARTIAL_DOMBoolean.FALSEに設定して、プラグインXMLデータを使用してSDOMを作成します。

他のすべてのノードからノードを手動で参照解除するには、freeNode()を起動します。次に例を示します。

Element root = doc.getDocumentElement();
 Node item = root.getFirstChild();
While (item != null)
{
     processItem(item);
     Node tmp = item;
     item = item.getNextSibling();
     ((XMLNode)tmp).freeNode();
}

ノードの参照解除によって、SDOMツリーからノードは削除されません。ノードは、その親や兄弟関係からアクセスおよび再作成可能です。ただし、ノードの参照解除後にノードにアクセスすると、ノードを保持する変数によってエラーがスローされます。

注意:

拡張性のないDOMではfreeNodeの起動は適用されません。

12.3.4.2.4 シャドウ・コピーの使用

シャドウ・コピーでは、DOMノードでデータを共有することによってデータのレプリケーションを回避します。

XML処理の共通操作であるクローン作成は、SDOMで簡単に実行できます。つまり、copyメソッドではコピーされたフラグメントのルート・ノードのみが作成され、サブツリーはオンデマンドでのみ拡張されます。

DOMノード自体は共有されません。基礎となるデータは共有されます。DOM仕様では、クローンとそのオリジナルではノードIDおよび親ノードを別のものにする必要があります。

12.3.4.2.5 DOM更新の合体

DOM APIは、ノードの追加および削除、値の設定、削除、変更および挿入などの更新操作をサポートします。

DOMがプラグインXMLデータで作成されると、基礎となるデータはDOMの外部とみなされます。DOM更新は、DOM APIから表示可能ですがデータ・ソースは同一のままです。通常の更新操作は使用可能ですが、相互に妨害はしません。

変更済のDOMを永続にするには、DOMを明示的に保存する必要があります。保存によって変更がオリジナル・データとマージされ、永続格納にデータがシリアライズされます。変更したDOMを明示的に保存しない場合は、トランザクションを終了すると変更が失われます。

12.3.4.2.6 PageManagerインタフェースを使用した内部データのサポート

PageManagerインタフェースを使用して、SDOMでバイナリ・データのバックエンド記憶域を使用できるようにする方法を示します。

XMLテキストがDOMParserで解析され、SDOMを作成するよう構成されている場合、内部データはバイナリXMLの形式でキャッシュされ、DOM APIレイヤーは内部データの上位で構築されます。バイナリXMLはDOMノードよりさらにコンパクトであるため、これによりスケーラビリティが増大されます。

追加のスケーラビリティに関しては、SDOMはPageManagerインタフェースを介してバイナリ・データのバックエンド格納を使用できます。バイナリ・データは、使用していないメモリーと交換可能です。

次のコードでは、PageManagerインタフェースの使用方法を示します。

DOMParser parser = new DOMParser();
parser.setAttribute(PARTIAL_DOM, Boolean.TRUE); //enable SDOM
parser.setAttribute(PAGE_MANAGER, new FilePageManager("pageFile"));
...
// DOMParser other configuration
parser.parse(fileURL);
XMLDocument doc = parser.getDocument();

PageManagerインタフェースを使用しない場合、パーサーはバイナリXMLとして文書全体をキャッシュします。

12.3.4.3 構成可能なDOM設定の使用

XMLDOMImplementationクラスを使用してDOMを作成する場合、setAttributeメソッドを使用することによって、異なるアプリケーション用にDOMを構成し、効率を最大にできます。

public void setAttribute(String name, Object value) throws IllegalArgumentException

SDOMの場合、PARTIAL_DOMおよびACCESS_MODE属性に対してsetAttributeを起動します。

注意:

新規の属性値が影響するのは次のDOMであり、現在のものではありません。したがって、XMLDOMImplementationのインスタンスを使用して、別の構成でDOMを作成できます。

12.3.4.3.1 PARTIAL_DOM属性

PARTIAL_DOM属性によって、作成されるDOMが部分的(つまり、拡張性がある)かどうかが決まります。その値がTRUEの場合、作成されるDOMは拡張性があります(つまり、使用されていないノードは解放され、必要に応じて再作成されます)。その値がFALSEの場合、作成されるDOMは拡張性がありません。

12.3.4.3.2 ACCESS_MODE属性

ACCESS_MODE属性(SDOMおよび拡張性のないDOMの両方に適用される)は、作成されるDOMへのアクセスを制御します。

表12-8に、この属性の値を最も制限の弱いものから強いものの順に示します。

表12-8 ACCESS_MODE属性の値

DOMアクセス パフォーマンス上の利点

UPDATEABLE

すべての更新操作が許可されます。これはデフォルト値で、XDK DOM実装での下位互換性用です。

READ_ONLY

DOM更新操作は許可されません。ノードの作成(クローン作成など)は、新規ノードがDOMツリーに追加されない場合にのみ許可されます。

書込みバッファは作成されません。

FORWARD_READ

前方ナビゲーション(たとえば、getFirstChild().getNextSibling()getLastChild()など)、および親や祖先ノードへのアクセスは許可されます。後方ナビゲーション(たとえば、getPreviousSibling()など)は許可されません。

前の兄弟関係リンクは作成されません。

STREAM_READ

SAXイベント・アクセスのような、文書内の順でのノードのストリームに限定されます。

現在のノードは、文書内の順で最後にアクセスされたノードです。アプリケーションは変数内にノードを保持し、再度アクセスできますが、DOMメソッドを使用して現在のノードより前のノード(親または祖先以外)にアクセスすると、エラーが発生します。次に例を示します。

  • 親は現在のノードより前ですが、これは許可されます。

    Node parent = currentNode.getParentNode();
    
  • 現在のノードが親の最初の子ではない場合、これはエラーになります。

    Node child = parent.getFirstChild();
    
  • 要素属性へのアクセスは常に許可されます。

    Attribute attr = parent.getFirstAttribute();

DOMでは、親リンクのみ保持され、ノードの位置は保持されません。したがって、開放されたノードを再作成する必要はありません。

12.3.4.4 SDOMでのFast Infosetの使用

XDK/JにFast Infosetを使用するモデルにより、JavaでXMLコンテンツを使用中にFast Infoset技術を使用できます。

注意:

Fast Infosetは入力にのみ使用します。出力には、CSXまたはXTIを使用します。

この例では、シリアライザを使用してXMLデータをFastInfoset BinaryStreamにエンコードします。

public com.sun.xml.fastinfoset.sax.SAXDocumentSerializer getSAXDocumentSerializer();
public com.sun.xml.fastinfoset.stax.StAXDocumentSerializer getStAXDocumentSerializer();

クラスoracle.xml.scalable.BinaryStreamは、バッファ管理と抽象ページI/Oビューを提供するデータ管理コンポーネントで、様々なタイプのデータ・ストレージのデコードをサポートします。

BinaryStreamInfosetReaderは、DOMでバイナリからデータを読み取るためのoracle.xml.scalable.InfosetReaderの実装です。この実装により、基本的なデコーダsun.com.xml.fasterinfoset.Decoderが拡張され、シーク操作およびスキップ操作のサポートが追加されます。

Fast InfosetをStreaming API for XML (StAX)およびSAXとともに使用して、DOMを作成できます。SDOMを作成するために、前の例および次の例のルーチンを使用できます。

String xmlFile, fiFile;
FileInputStream xin = new FileInputStream(new File(xmlFile));
XML_SAX_FI figen = new XML_SAX_FI();
FileOutputStream outfi = new FileOutputStream(new File(fiFile));
figen.parse(xin, outfi);
outfi.close();

import oracle.xml.scalable.BinaryStream;

BinaryStream stream = BinaryStream.newInstance(SUN_FI);
stream.setFile(new File(fiFile));
InfosetReader reader = stream.getInfosetReader();
XMLDOMImplementation dimp = new  XMLDOMImplementation();
dimp.setAttribute(XMLDocument.SCALABLE_DOM, Boolean.TRUE);
XMLDocument doc = (XMLDocument) dimp.createDocument(reader);
12.3.4.5 SDOMアプリケーション

SDOMを作成および使用するアプリケーションを示します。

このアプリケーションでは、SDOMを作成および使用します。

XMLDOMImplementation domimpl = new XMLDOMImplementation();
domimpl.setAttribute(XMLDocument.SCALABLE_DOM, Boolean.TRUE);
domimpl.setAttribute(XMLDocument.ACCESS_MODE,XMLDocument.UPDATEABLE);
XMLDocument scalableDoc = (XMLDocument) domimpl.createDocument(reader);

次のアプリケーションでは、「JavaでのバイナリXMLの使用」で説明されているバイナリXMLに基づいてSDOMを作成および使用します。

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);
12.3.4.6 XDK Java DOMの改善

XDKでは、DOMレベル3のコア仕様、W3C勧告をサポートしています。

関連項目:

DOMレベル3の詳細は、Document Object Model (DOM) Level 3 Core Specificationを参照してください

12.3.5 名前空間を使用したDOM操作の実行

DOM2Namespace.javaには、パーサーの単純な使用方法とDOM APIへの名前空間による拡張が示されています。プログラムは、XML文書を受け取って解析し、文書内の要素と属性を出力します。

この項には、DOM2Namespace.javaプログラムのコードの一部が含まれています。詳細は、プログラム自体を参照してください。

「基本的な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ツリー内のすべての要素のリストを取得します。次に、リスト内の各アイテムをループし、各ElementnsElementにキャストします。各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();
   }
}

12.3.6 イベントを使用したDOM操作の実行

EventSample.javaには、イベント・リスナーにイベントを登録する方法が示されています。たとえば、指定されたDOM要素にノードが追加されると、イベントがトリガーされます。これにより、リスナーがイベントに関する情報を出力します。

この項には、EventSample.javaプログラムのコードの一部が含まれています。詳細は、プログラム自体を参照してください。

EventSample.javaプログラムは次のステップを実行します。

  1. イベント・リスナーをインスタンス化します。

    登録された変更によりイベントがトリガーされると、イベントがイベント・リスナーに渡されて処理されます。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);
       }
    }
    
  2. 新規XMLDocumentをインスタンス化し、getImplementation()を起動してDOMImplementationオブジェクトを取得します。

    EventSample.javaの次のコード部分のように、hasFeature()メソッドを起動して、この実装でサポートされる機能を決定します。

    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"));
    
  3. 目的のイベントをリスナーに登録します。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);
    ...
    
  4. EventSample.javaの次のコード部分のように、イベントをトリガーするアクションを実行します。これらのイベントは、リスナーに渡されて処理されます。
    att.setNodeValue("abc");
    el.appendChild(el1);
    el.appendChild(text);
    text.setNodeValue("xyz");
    doc1.removeChild(el);

12.3.7 範囲を使用したDOM操作の実行

W3C DOM仕様によると、範囲DocumentDocumentFragmentまたはAttrのコンテンツの範囲を識別します。範囲によって、範囲の開始と終了に対応する1組の境界点の間にあるコンテンツを選択します。

表12-9に、XMLDocumentを介してアクセスできる範囲メソッドを示します。

表12-9 範囲クラスのメソッド

メソッド 説明

cloneContents()

範囲のコンテンツを複製します。

deleteContents()

範囲のコンテンツを削除します。

getCollapsed()

範囲が閉じている場合にTRUEを戻します。

getEndContainer()

範囲が終了するノードを取得します。

getStartContainer()

範囲が開始するノードを取得します。

selectNode()

ノードとそのコンテンツを選択します。

selectNodeContents()

ノードのコンテンツを選択します。

setEnd()

範囲の終了を示す属性を設定します。

setStart()

範囲の開始を示す属性を設定します。

DOMRangeSample.javaプログラムは、範囲で実行できる操作をいくつか示します。この項には、DOMRangeSample.javaプログラムのコードの一部が含まれています。詳細は、プログラム自体を参照してください。

「基本的なDOM解析の実行」の最初の4つのステップ(パーサー作成からgetDocument()の起動まで)は、DOMRangeSample.javaの場合も同じです。DOMRangeSample.javaプログラムは次のステップを実行します。

  1. DOMRangeSample.javaの次のコード部分のように、getDocument()を起動してXMLDocumentを作成した後、createRange()で範囲オブジェクトを作成し、setStart()およびsetEnd()を起動してその境界を設定します。
    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);
    
  2. XMLDocumentメソッドを起動して範囲に関する情報を取得し、そのコンテンツを操作します。

    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());

12.3.8 TreeWalkerを使用したDOM操作の実行

XDKは、W3C DOMレベル2 Traversal and Range仕様で定義されているNodeFilterおよびTreeWalkerインタフェースを実装します。

ノード・フィルタは、特定のタイプのNodeオブジェクトをフィルタ処理するオブジェクトです。たとえば、エンティティ参照ノードをフィルタ処理によって除外し、要素ノードと属性ノードを受け入れることができます。NodeFilterインタフェースを実装し、次にNodeオブジェクトをacceptNode()メソッドに渡すことにより、ノード・フィルタを作成します。通常、acceptNode()メソッド実装はgetNodeType()を起動してノードのタイプを取得し、それをELEMENT_TYPEATTRIBUTE_TYPEなどの静的変数と比較してから、結果に基づいて表12-10に示された静的フィールドの1つを戻します。

表12-10 NodeFilterインタフェースの静的フィールド

フィールド 説明

FILTER_ACCEPT

ノードを受け入れます。NodeIteratorまたはTreeWalkerで定義されているナビゲーション・メソッドは、このノードを戻します。

FILTER_REJECT

ノードを拒否します。NodeIteratorまたはTreeWalkerに定義されたナビゲーション・メソッドはこのノードを戻しません。TreeWalkerの場合、このノードの子も拒否されます。NodeIteratorでは、FILTER_REJECTFILTER_SKIPと同義とみなされます。

FILTER_SKIP

この単一ノードをスキップします。NodeIteratorまたはTreeWalkerに定義されたナビゲーション・メソッドはこのノードを戻しません。NodeIteratorTreeWalkerの両方で、このノードの子は対象です。

TreeWalkerオブジェクトを使用し、whatToShowフラグおよびTreeWalkerオブジェクトのフィルタで定義されている文書のビューを使用して文書ツリーまたはサブツリーを検索できます。

TreeWalkerオブジェクトを作成するには、次の項目を指定してXMLDocument.createTreeWalker()メソッドを使用します。

  • ツリーまたはサブツリーのルート・ノード

  • 論理ビューに含めるノードのタイプを管理するフラグ

  • ノード・フィルタ(オプション)

  • エンティティ参照とその子孫を含めるかどうかを決定するフラグ

表12-11で、org.w3c.dom.traversal.TreeWalkerインタフェースのメソッドについて説明します。

表12-11 TreeWalkerインタフェース・メソッド

メソッド 説明

firstChild()

ツリー・ウォーカーを現在のノードの最初に表示可能な子に移動し、新規ノードを戻します。現在のノードに表示可能な子がない場合は、メソッドはnullを戻し、現在のノードを保持します。

getRoot()

ツリー・ウォーカーのルート・ノード(TreeWalkerオブジェクトの作成時の指定)を取得します。

lastChild()

ツリー・ウォーカーを現在のノードの最後に表示可能な子に移動し、新規ノードを戻します。現在のノードに表示可能な子がない場合は、メソッドはnullを戻し、現在のノードを保持します。

nextNode()

ツリー・ウォーカーを文書内の現在のノードとの相対順序で次に表示可能な子に移動し、新規ノードを戻します。

TreeWalkerSample.javaプログラムは、ノード・フィルタとツリー・ウォーカーで実行できる操作をいくつか示します。この項には、TreeWalkerSample.javaプログラムのコードの一部が含まれています。詳細は、プログラム自体を参照してください。

「基本的なDOM解析の実行」の最初の4つのステップ(パーサー作成からgetDocument()の起動まで)は、TreeWalkerSample.javaの場合も同じです。TreeWalkerSample.javaプログラムは次のステップを実行します。

  1. ノード・フィルタ・オブジェクトを作成します。

    TreeWalkerSample.javaの次のコード部分のように、NodeFilterインタフェースを実装するnfクラスのacceptNode()メソッドは、getNodeType()を起動してノードのタイプを取得します。

    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;
      }
    }
    
  2. XMLDocument.createTreeWalker()メソッドを起動してツリー・ウォーカーを作成します。

    TreeWalkerSample.javaの次のコード部分は、XMLDocumentのルート・ノードをツリー・ウォーカーのルート・ノードとして使用し、ツリー内のすべてのノードを含めます。

    XMLDocument doc = parser.getDocument();
    ...
    TreeWalker tw = doc.createTreeWalker(doc.getDocumentElement(),NodeFilter.SHOW_ALL,n2,true);
    
  3. TreeWalkerSample.javaの次のコード部分のように、TreeWalkerオブジェクトのルート要素を取得します。
    XMLNode nn = (XMLNode)tw.getRoot();
    
  4. ツリーを検索します。

    TreeWalkerSample.javaの次のコード部分では、TreeWalker.nextNode()メソッドを起動することで文書内の順序に従ってツリーを移動します。

    while (nn != null)
    {
      System.out.println(nn.getNodeName() + " " + nn.getNodeValue());
      nn = (XMLNode)tw.nextNode();
    }
    

    TreeWalkerSample.javaの次のコード部分では、firstChild()メソッドを起動してツリーの左の深さを移動します。

     while (nn != null)
     {
       System.out.println(nn.getNodeName() + " " + nn.getNodeValue());
       nn = (XMLNode)tw.firstChild();
     }
    

    lastChild()メソッドを起動してツリーの右の深さを移動できます。

12.4 SAXを使用したXMLの解析

Simple API for XML (SAX)は、イベントベースのXML解析の標準インタフェースです。

12.4.1 SAX API for Javaの使用

レベル1およびレベル2のバージョンでリリースされたSAX APIのインタフェースとクラスについて説明します。

インタフェースとクラスは、次のとおりです。

  • Oracle XML Parserで実装されるインタフェース

  • アプリケーションで実装する必要のあるインタフェース(表12-12を参照)

  • 標準SAXクラス

  • org.xml.sax.helperパッケージのSAX 2.0ヘルパー・クラス(表12-13を参照)

  • nulパッケージ内のデモンストレーション・クラス

表12-12に、アプリケーションで実装する必要のあるSAX 2.0インタフェースをリストし、説明します。

表12-12 SAX 2.0ハンドラ・インタフェース

インタフェース 説明

ContentHandler

XMLパーサーから通知を受信します。主なイベント処理メソッドであるstartDocument()endDocument()startElement()およびendElement()を実装します。これらのメソッドは、XMLパーサーがXMLタグを識別すると起動されます。メソッドcharacters()およびprocessingInstruction()を実装します。これらのメソッドは、XMLパーサーがXML要素またはインライン処理命令内でテキストを検出した場合に起動されます。

DeclHandler

XML文書内のDTD宣言に関する通知を受信します。

DTDHandler

通知および未解析(バイナリ)エンティティを処理します。

EntityResolver

文書内のURIのリダイレクトをサポートします。resolveEntity()メソッドを実装します。このメソッドは、XMLパーサーがURIで示されたデータを識別する必要がある場合に起動されます。

ErrorHandler

パーサー・エラーを処理します。メソッドerror()fatalError()およびwarning()を実装します。これらのメソッドは、様々な解析エラーに対応して起動されます。

LexicalHandler

コメントや文字データ(CDATA)セクション境界などの字句情報に関する通知を受信します。

表12-13に、SAX 2.0ヘルパー・クラスをリストし、説明します。

表12-13 SAX 2.0ヘルパー・クラス

クラス 説明

AttributeImpl

AttributeListの永続コピーを作成します。

DefaultHandler

表12-12のインタフェースのデフォルト実装によるベース・クラス。

LocatorImpl

解析中の指定されたポイントでロケータの値の永続スナップショットを作成します。

NamespaceSupport

XML名前空間をサポートします。

XMLFilterImpl

イベントのストリームを変更するアプリケーションによって使用されるベース・クラス。

XMLReaderFactory

SAXパーサーの動的ロードをサポートします。

図12-5に、SAXパーサーの作成方法と、そのパーサーを使用して入力文書を解析する方法を示します。

図12-5 SAXParserクラスの使用

図12-5の説明が続きます
「図12-5 SAXParserクラスの使用」の説明

SAXを使用した入力XML文書の解析の基本ステップは次のとおりです。

  1. SAXParserオブジェクトを作成し、そのプロパティを構成します。

    たとえば、検証モードを設定します。構成メソッドについては、表12-5を参照してください。

  2. イベント・ハンドラをインスタンス化します。

    アプリケーションで表12-12のハンドラ・インタフェースを実装する必要があります。

  3. XMLパーサーにイベント・ハンドラを登録します。

    このステップによって、パーサーは特定のイベントが発生したときに適切なメソッドを起動できます。イベント・ハンドラを登録するためのSAXParserのメソッドの詳細は、表12-14を参照してください。

  4. SAXParser.parse()メソッドを使用して入力ドキュメントを解析します。

    すべてのSAXインタフェースは、同期操作を前提としています。そのため、解析メソッドは解析が完了するまで結果を戻しません。リーダーは、次のイベントを通知する前にイベント・ハンドラのコールバックが結果を戻すまで待機する必要があります。

    SAXParser.parse()メソッドが起動された場合、プログラムでは、アプリケーションで実装された複数のコールバック・メソッドの1つを起動します。メソッドは、イベント・ハンドラで実装されたContentHandlerErrorHandlerDTDHandlerおよびEntityResolverインタフェースにより定義されます。たとえば、アプリケーションは、開始要素を検出した際にstartElement()メソッドを起動できます。

表12-14に、イベント・ハンドラを登録するためのSAXParserのメソッドをリストして説明し、各メソッドを使用する場合について説明します。アプリケーションは、解析処理中に新規または別のハンドラを登録できます。SAXパーサーは、新たに登録されたハンドラの使用をただちに開始する必要があります。

表12-14 イベント・ハンドラを登録するためのSAXParserのメソッド

メソッド 説明

setContentHandler()

コンテンツ・イベント・ハンドラをアプリケーションに登録します。

org.xml.sax.DefaultHandlerクラスはorg.xml.sax.ContentHandlerインタフェースを実装します。

setDTDHandler()

DTDイベント・ハンドラをアプリケーションに登録します。

アプリケーションでDTDハンドラを登録しない場合、SAXパーサーにより報告されるDTDイベントは無視され、警告は出力されません。

setErrorHandler()

エラー・イベント・ハンドラをアプリケーションに登録します。

アプリケーションでエラー・ハンドラを登録しない場合、SAXパーサーにより報告されるすべてのエラー・イベントは無視され、警告は出力されません。予想外の不具合を回避するため、すべてのSAXアプリケーションにエラー・ハンドラを実装することを強くお薦めします。

setEntityResolver()

エンティティ・リゾルバをアプリケーションに登録します。

アプリケーションでエンティティ・リゾルバを登録しない場合、XMLReaderは独自のデフォルトの解決を実行します。

12.4.2 基本的なSAX解析の実行

SAXSample.javaには、SAX解析の基本ステップが示されています。SAXSampleクラスはHandlerBaseを拡張します。プログラムは、入力としてXMLファイルを受け取って解析し、ファイルのコンテンツに関する情報を出力します。

SAXSample.javaプログラムは次のステップ(プログラムのコード部分とともに示す)を実行します。

  1. Locatorを格納します。
    Locator locator;
    

    Locatorは、SAXイベントを文書の場所に関連付けます。SAXパーサーは、Locatorインスタンスをコンテンツ・ハンドラのsetDocumentLocator()メソッドに渡すことにより、アプリケーションに場所情報を提供します。アプリケーションでは、オブジェクトを使用して、XMLソース文書内の他の任意のコンテンツ・ハンドラ・イベントの場所を取得できます。

  2. 新規イベント・ハンドラをインスタンス化します。
    SAXSample sample = new SAXSample();
    
  3. SAXパーサーをインスタンス化し、構成します。
    Parser parser = new SAXParser();
    ((SAXParser)parser).setValidationMode(SAXParser.DTD_VALIDATION);
    

    前述のコードでは、モードをDTD検証に設定します。

  4. SAXパーサーにイベント・ハンドラを登録します。
    parser.setDocumentHandler(sample);
    parser.setEntityResolver(sample);
    parser.setDTDHandler(sample);
    parser.setErrorHandler(sample);
    

    SAXParserクラスの登録メソッドを使用できますが、イベント・ハンドラ・インタフェースはユーザーが実装する必要があります。

    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());
    }
    
  5. 入力XML文書を解析します。
    parser.parse(DemoUtil.createURL(argv[0]).toString());
    

    前述のコードでは、文書をURLに変換して解析します。

12.4.3 名前空間を使用した基本的なSAX解析の実行

SAX2Namespace.javaでは、XMLDefaultHandlerというイベント・ハンドラをorg.xml.sax.helpers.DefaultHandlerクラスのサブクラスとして実装します。

ContentHandlerインタフェースを実装する最も簡単な方法は、org.xml.sax.helpers.DefaultHandlerクラスを拡張することです。DefaultHandlerクラスは、イベントを処理するためのデフォルトの動作をいくつか提供しますが、一般的な動作は何も行わないことです。

SAX2Namespace.javaでは、関連するイベントに対してのみメソッドをオーバーライドします。具体的には、XMLDefaultHandlerクラスはstartElement()およびendElement()という2つのメソッドのみ実装します。SAXParserは、XML文書内に新規要素を検出するとstartElementイベントをトリガーし、startElement()メソッドが要素の名前空間情報を出力します。

SAX2Namespace.javaサンプル・プログラムは次のステップ(プログラムのコード部分とともに示す)を実行します。

  1. DefaultHandler型の新規イベント・ハンドラをインスタンス化します。
    DefaultHandler defHandler = new XMLDefaultHandler();
    
  2. SAXパーサーを作成し、その検証モードを設定します。
    Parser parser = new SAXParser();
    ((SAXParser)parser).setValidationMode(SAXParser.DTD_VALIDATION);
    

    前述のコードでは、モードをDTD検証に設定します。

  3. SAXパーサーにイベント・ハンドラを登録します。
    parser.setContentHandler(defHandler);
    parser.setEntityResolver(defHandler);
    parser.setDTDHandler(defHandler);
    parser.setErrorHandler(defHandler);
    

    前述のコードでは、入力文書、DTD、エンティティおよびエラーのハンドラを登録します。

    次のコードは、XMLDefaultHandler実装を示します。startElement()およびendElement()メソッドは、各要素の修飾名、ローカル名および名前空間URIを出力します(これらの用語の説明は、表12-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);
       }
    }
    
  4. 入力XML文書を解析します。
    parser.parse(DemoUtil.createURL(argv[0]).toString());
    

    前述のコードでは、文書をURLに変換して解析します。

12.4.4 XMLTokenizerを使用したSAX解析の実行

単純なSAXパーサーをXMLTokenizerクラスのインスタンスとして作成し、パーサーを使用して入力XMLをトークン化できます。

表12-15に、このクラスの有用なメソッドを示します。

表12-15 XMLTokenizerのメソッド

メソッド 説明

setToken()

XMLトークン化機能の新規トークンを登録します。

setErrorStream()

エラーの出力ストリームを登録します。

tokenize()

入力XMLをトークン化します。

Tokenizer機能のあるSAXパーサーは、XMLTokenインタフェースを実装します。XMLTokenのコールバック・メソッドはtoken()です。このメソッドは、XMLトークンおよび対応する値を受け取り、アクションを実行します。たとえば、トークン名に続いてトークンの値を出力するようにtoken()を実装できます。

Tokenizer.javaサンプル・プログラムでは、入力としてXML文書を受け取って解析し、XMLトークンのリストを出力します。プログラムでは、次のステップ(プログラムのコード部分とともに示す)を実行するdoParse()メソッドを実装します。

  1. 入力XMLストリームからURLを作成します。
    URL url = DemoUtil.createURL(arg);
    
  2. XMLTokenizerパーサーを作成します。
    parser  = new XMLTokenizer ((XMLToken)new Tokenizer());
    
  3. 出力エラー・ストリームを登録します。
    parser.setErrorStream  (System.out);
    
  4. トークンをパーサーに登録します。
    parser.setToken (STagName, true);
    parser.setToken (EmptyElemTag, true);
    parser.setToken (STag, true);
    parser.setToken (ETag, true);
    parser.setToken (ETagName, true);
    ...
    
  5. XML文書をトークン化します。
    parser.tokenize (url);
    

    token()コールバック・メソッドは、特定のトークンが検出されたときに実行するアクションを決定します。次のコードは、このメソッドの実装の一部です。

    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;
       }
    }

12.5 JAXPを使用したXMLの解析

JAXPでは、JavaプログラムでSAXおよびDOMパーサーとXSLTプロセッサを使用できます。

12.5.1 JAXP構造

JAXPは、パーサーのプラガビリティのためのthinレイヤーを提供する抽象クラスで構成されます。Oracleは、Sun社のリファレンス実装に基づいてJAXPを実装しています。

表12-16に、JAXPを構成するパッケージをリストし、説明します。

表12-16 JAXPパッケージ

パッケージ 説明

javax.xml.parsers

DOM 2.0およびSAX 1.0パーサーの標準APIを提供します。SAXParserおよびDocumentBuilderなどのベンダーに依存しないファクトリ・クラスが含まれています。DocumentBuilderは、DOM準拠のDocumentオブジェクトを作成します。

javax.xml.transform

XML変換の処理と、ソースから結果への変換の実行のための汎用APIを定義します。

javax.xml.transform.dom

DOM固有の変換APIを提供します。

javax.xml.transform.sax

SAX2固有の変換APIを提供します。

javax.xml.transform.stream

ストリーム固有およびURI固有の変換APIを提供します。

12.5.2 JAXPを介したSAX APIの使用

ファクトリ設計パターンに依存して、JAXPを使用して新規SAXパーサー・エンジンを作成できます。

図12-6に、基本プロセスを示します。

図12-6 JAXPを使用したSAX解析

図12-6の説明が続きます
「図12-6 JAXPを使用したSAX解析」の説明

JAXPを介したSAXでの解析の基本ステップは、次のとおりです。

  1. SAXParserFactoryクラスで新規SAXパーサー・ファクトリを作成します。
  2. ファクトリを構成します。
  3. 新規SAXパーサー(SAXParser)オブジェクトをファクトリから作成します。
  4. SAXパーサーのイベント・ハンドラを設定します。
  5. 入力XML文書を解析します。

12.5.3 JAXPを介したDOM APIの使用

ファクトリ設計パターンに基づき、JAXPを使用して新規DOM文書ビルダー・エンジンを作成できます。

図12-7に、基本プロセスを示します。

図12-7 JAXPを使用したDOM解析

図12-7の説明が続きます
「図12-7 JAXPを使用したDOM解析」の説明

JAXPを介したDOMでの解析の基本ステップは、次のとおりです。

  1. DocumentBuilderFactoryクラスで新規DOMパーサー・ファクトリを作成します。
  2. ファクトリを構成します。
  3. 新規DOMビルダー(DocumentBuilder)オブジェクトをファクトリから作成します。
  4. DOMビルダーのエラー・ハンドラとエンティティ・リゾルバを設定します。
  5. 入力XML文書を解析します。

12.5.4 JAXPを介したXMLの変換

JAXPを介したXML変換の基本ステップについて説明します。

ステップは次のとおりです。

  1. TransformerFactoryクラスで新規トランスフォーマ・ファクトリを作成します。
  2. ファクトリを構成します。
  3. ファクトリから新規トランスフォーマを作成し、XSLTスタイルシートを指定します。
  4. トランスフォーマを構成します。
  5. 文書を変換します。

12.5.5 JAXPを使用した解析

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.javareader()メソッドでは、次のステップ(プログラムのコード部分とともに示す)を使用して、SAXでXML文書を解析する簡単な方法を示します。

  1. TransformerFactoryの新規インスタンスを作成し、SAXTransformerFactoryにキャストします。
    TransformerFactory tfactory = TransformerFactory.newInstance();
    SAXTransformerFactory stfactory = (SAXTransformerFactory)tfactory;
    
  2. スタイルシートからStreamSourceオブジェクトを作成し、それをファクトリ・メソッドnewXMLFilter()に渡すことにより、XMLリーダーを作成します。
    URL xslURL = createURL("jaxpone.xsl");
    String xslID = xslURL.toString();
    ...
    StreamSource streamSource = new StreamSource(xslID);
    XMLReader reader = stfactory.newXMLFilter(streamSource);
    

    newXMLFilter()は、指定されたSourceを変換命令として使用するXMLFilterオブジェクトを戻します。

  3. コンテンツ・ハンドラを作成し、XMLリーダーに登録します。
    ContentHandler contentHandler = new oraContentHandler();
    reader.setContentHandler(contentHandler);
    

    前述のコードでは、デモ・ディレクトリ内のoraContentHandler.javaプログラムをコンパイルしてクラスoraContentHandlerのインスタンスを作成します。

    次のコードでは、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");
       }
       ...
    
  4. InputSourceXMLReader.parse()メソッドに渡すことにより、入力XML文書を解析します。
    InputSource is = new InputSource(xmlID);
    reader.parse(is);

12.5.6 JAXPを使用した基本的な変換の実行

JAXPを使用して基本的な変換を実行できます。

JAXPでは、次のタイプの入力を変換できます。

  • XML文書

  • XSLスタイルシート

  • oraContentHandler.javaに定義されているContentHandlerクラス

次に、JAXPを使用した基本的な変換の実行の例を示します。

  • identity()メソッドを使用して、出力XML文書が入力XML文書と同じになる変換を実行できます。

  • xmlFilterChain()メソッドを使用して、連鎖内の3つのスタイルシートを適用できます。

  • インタフェースSourceの任意のクラスをインタフェースResultのクラスに(DOMSourceDOMResultに、StreamSourceStreamResultに、SAXSourceSAXResultに、など)変換できます。

プログラムJAXPExamples.javabasic()メソッドでは、次のステップ(プログラムのコード部分とともに示す)を使用して基本的なXSLT変換を実行する方法を示します。

  1. TransformerFactoryの新規インスタンスを作成します。
    TransformerFactory tfactory = TransformerFactory.newInstance();
    
  2. ファクトリから新規XSLトランスフォーマを作成し、変換に使用するスタイルシートを指定します。
    URL xslURL = createURL("jaxpone.xsl");
    String xslID = xslURL.toString();
    ...
    Transformer transformer = tfactory.newTransformer(new StreamSource(xslID));
    

    前述のコードでは、スタイルシートはjaxpone.xslです。

  3. ストリーム・ソースを入力XML文書に設定します。
    URL xmlURL = createURL("jaxpone.xml");
    String xmlID = xmlURL.toString();
    ...
    StreamSource source = new StreamSource(xmlID);
    

    前述のコードでは、ストリーム・ソースはjaxpone.xmlです。

  4. StreamSourceの文書をStreamResultに変換します。
    transformer.transform(source, new StreamResult(System.out));

12.6 XMLの圧縮と解凍

XDKでは、SAXまたはDOMを使用してXMLを解析し、解析したデータを圧縮バイナリ・ストリームに書き込むことができます。反対に、バイナリ・ストリームを解凍してXMLデータを再構築することもできます。

12.6.1 DOMオブジェクトの圧縮

DOMCompression.javaには、DOMの圧縮の基本ステップが示されています。最も重要なDOMの圧縮メソッドはXMLDocument.writeExternal()で、オブジェクトに関する情報でバイナリ圧縮ストリームを作成することにより、オブジェクトの状態を保存します。

DOMCompression.javaプログラムでは、次のステップ(プログラムのコード部分とともに示す)を使用します。

  1. DOMパーサーを作成し、入力XML文書を解析し、DOM表現を取得します。
    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();
            ...
    

    この方法の詳細は、「基本的なDOM解析の実行」を参照してください。

  2. FileOutputStreamを作成し、シリアライズのためにObjectOutputStream内にラップします。
    OutputStream os = new FileOutputStream("xml.ser");
    ObjectOutputStream oos = new ObjectOutputStream(os);
    
  3. XMLDocument.writeExternal()を起動して、オブジェクトをファイルにシリアライズします。
    doc.writeExternal(oos);
    

    このメソッドは、このオブジェクトに関する情報でバイナリ圧縮ストリームを作成することにより、オブジェクトの状態を保存します。

12.6.2 DOMオブジェクトの解凍

DOMDeCompression.javaには、DOMの解凍の基本ステップが示されています。最も重要なDOMの解凍メソッドはXMLDocument.readExternal()で、writeExternal()メソッドにより書き込まれた情報(圧縮ストリーム)を読み取り、オブジェクトを復元します。

DOMDeCompression.javaプログラムでは、次のステップ(プログラムのコード部分とともに示す)を使用します。

  1. 圧縮ファイルのファイル入力ストリームを作成し、ObjectInputStream内にラップします。
    InputStream is;
    ObjectInputStream ois;
    ...
    is = new FileInputStream("xml.ser");
    ois = new ObjectInputStream(is);
    

    前述のコードにより、「DOMオブジェクトの圧縮」で作成された圧縮ファイルからFileInputStreamが作成されます。

  2. 新規XML文書オブジェクトを作成して、解凍したデータを格納します。
    XMLDocument serializedDoc = null;
    serializedDoc = new XMLDocument();
    
  3. XMLDocument.readExternal()を起動して、圧縮ファイルを読み取ります。
    serializedDoc.readExternal(ois);
    serializedDoc.print(System.out);
    

    前述のコードでは、データをSystem.outに出力します。

12.6.3 SAXオブジェクトの圧縮

SAXCompression.javaには、SAXを使用してファイルを解析し、圧縮ストリームをファイルに書き込む基本ステップが示されています。重要なクラスはCXMLHandlerBaseで、SAXイベントに基づいてXMLデータを圧縮するSAX Handlerです。

SAX圧縮を使用するには、このインタフェースを実装し、Parser.setDocumentHandler()を起動してSAXパーサーに登録します。

SAXCompression.javaプログラムでは、次のステップ(プログラムのコード部分とともに示す)を使用します。

  1. FileOutputStreamを作成し、ObjectOutputStream内にラップします。
    String compFile = "xml.ser";
    FileOutputStream outStream = new FileOutputStream(compFile);
    ObjectOutputStream out = new ObjectOutputStream(outStream);
    
  2. SAXイベント・ハンドラを作成します。
    CXMLHandlerBase cxml = new CXMLHandlerBase(out);
    
    

    CXMLHandlerBaseクラスは、ContentHandlerDTDHandlerEntityResolverおよびErrorHandlerインタフェースを実装します。

  3. SAXパーサーを作成します。
    SAXParser parser = new SAXParser();
    
  4. SAXパーサーを構成します。
    parser.setContentHandler(cxml);
    parser.setEntityResolver(cxml);
    parser.setValidationMode(XMLConstants.NONVALIDATING);
    

    前述のコードでは、コンテンツ・ハンドラ、エンティティ・リゾルバおよび検証モードを設定します。

    注意:

    oracle.xml.comp.CXMLHandlerBaseDocumentHandlerContentHandlerの両方のインタフェースを実装しますが、SAX 2.0 ContentHandlerインタフェースを使用することをお薦めします。

  5. XMLを解析します。
    parser.parse(url);
    

    SAXCompression.javaプログラムは、シリアライズされたデータをObjectOutputStreamに書き込みます。

12.6.4 SAXオブジェクトの解凍

SAXDeCompression.javaには、SAXCompression.javaによって書き込まれたファイルからシリアライズされたデータを読み取る基本ステップが示されています。重要なクラスはCXMLParserで、圧縮ストリームからSAXイベントを再生成するXMLパーサーです。

SAXDeCompression.javaプログラムは次のステップ(プログラムのコード部分とともに示す)を実行します。

  1. SAXイベント・ハンドラを作成します。
    SampleSAXHandler xmlHandler = new SampleSAXHandler();
    
  2. CXMLParserクラスをインスタンス化することにより、SAXパーサーを作成します。
    CXMLParser parser = new CXMLParser();
    

    CXMLParserクラスは、圧縮ストリームからSAXイベントを生成することにより、その圧縮ストリームからのXML文書の再生成を実装します。

  3. SAXパーサーのイベント・ハンドラを設定します。
    parser.setContentHandler(xmlHandler);
    
  4. 圧縮ストリームを解析し、SAXイベントを生成します。
    parser.parse(args[0]);
    

    前述のコードでは、コマンドラインからファイル名を受け取り、XMLを解析します。

12.7 XML解析のヒントと方法

解析に関するいくつかのヒントと方法を示します。

12.7.1 DOMツリーからのノード値の抽出

XMLNodeクラスのselectNodes()メソッドを使用して、XSLが許可する選択パターンに基づいてDOMツリーまたはサブツリーからコンテンツを抽出できます。

selectNodes()のオプションの2つ目のパラメータを使用して、名前空間の接頭辞を解決できます。つまり、接頭辞付きの展開された名前空間URLを戻します。XMLElementクラスはNSResolverを実装するため、XMLElementオブジェクトの参照は、2つ目のパラメータとして送信できます。XMLElementは、入力文書に基づいて接頭辞を解決します。名前空間の定義をオーバーライドする場合、NSResolverインタフェースを使用できます。

例12-4のサンプル・コードでは、selectNodes()の使用方法を示します。

プログラムをテストするには、例12-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

例12-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

12.7.2 appendChild()を使用した文書のマージ

XMLElement.appendChild()を使用してXML文書をマージする方法について説明します。

ユーザーがクライアント側Javaフォームに入力でき、XML文書を取得できるプログラムを作成するために、Javaプログラムに次の変数を含めることができます。

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番目の方法のみ使用できます。

例12-5では、2つのツリー(e1の所有者文書はxmldoc1で、e2の所有者文書はxmldoc2)を使用します。appendChild()メソッドは、単一ツリー内でのみ機能します。したがって、XMLElement.appendChild()を起動すると、DOM例外WRONG_DOCUMENT_ERRが発生します。

異なるXML文書間におけるDOM文書のフラグメントまたはDOMノードのコピーおよび貼付けには、XMLDocument.importNode()メソッド(DOM 2で導入)およびXMLDocument.adoptNode()メソッド(DOM 3で導入)を使用します。例12-6のコメントでは、この方法を示します。

例12-5 appendChild()の不適切な使用方法

XMLDocument xmldoc1 = new XMLDocument();
XMLElement e1 = xmldoc1.createElement("person");
XMLDocument xmldoc2 = new XMLDocument();
XMLElement e2 = xmldoc2.createElement("firstname");
e1.appendChild(e2);

例12-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);

12.7.3 DTDの解析

DTDをロードして解析できます。

12.7.3.1 外部DTDのロード

DTDのロードおよび解析の手順を示します。

DOMParser.parse()メソッドを起動してXML文書をInputStreamとして解析する場合は、DOMParser.setBaseURL()メソッドを使用してJavaプログラム内で外部DTDを認識します。DOMParser.setBaseURL()は、DTDが公開されている場所を指します。

DTDのロードと解析の手順は次のとおりです。

  1. DTDをInputStreamとしてロードします。

    たとえば、次のコードでは/mydir/my.dtd外部DTDに対して文書を検証します。

    InputStream is = MyClass.class.getResourceAsStream("/mydir/my.dtd");
    

    前述のコードでは、DTDが指定されているCLASSPATH上の最初の相対位置にある./mydir/my.dtdが開かれます。JARファイルがCLASSPATHにある場合は、そのJARファイルも開かれます。

  2. DOMパーサーを作成し、検証モードを設定します。

    次に例を示します。

    DOMParser d = new DOMParser();
    d.setValidationMode(DTD_VALIDATION);
    
  3. DTDを解析します。

    たとえば、次のコードでは、InputStreamオブジェクトをDOMParser.parseDTD()メソッドに渡します。

    d.parseDTD(is, "rootelementname");
    
  4. 文書タイプを取得し、設定します。

    たとえば、次のコードでは、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);
    
  5. 入力XML文書を解析します。
    d.parse("mydoc.xml");
12.7.3.2 setDoctypeによるDTDのキャッシュ

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);

例12-7では、DOMParser.setDoctype()を起動してDTDをキャッシュします。

キャッシュされたDTDオブジェクトが検証に対してのみ使用される場合は、DOMParser.USE_DTD_ONLY_FOR_VALIDATION属性を設定します。

parser.setAttribute(DOMParser.USE_DTD_ONLY_FOR_VALIDATION,Boolean.TRUE);

DTDオブジェクトが検証に使用されない場合、XMLパーサーはDTDオブジェクトをコピーして、結果のDOMツリーに追加します。

例12-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);
 
        // Get the DOM tree and print
        XMLDocument doc = parser.getDocument();
        doc.print(new PrintWriter(System.out));
 
      }
      catch (Exception e)
      {
         System.out.println(e.toString());
      }
   }
}

12.7.4 XML Parserでのキャラクタ・セットの処理

パーサーを使用したキャラクタ・セットの処理に関するトピックを取り上げます。

12.7.4.1 オペレーティング・システム上でのXMLファイルのエンコーディングの検出

XMLパーサーを使用して、ファイル・システムに格納されたXMLファイルの文字エンコーディングを検出します。

オペレーティング・システム・ファイルに格納されたXMLファイルを読み取る場合は、FileReaderクラスを使用しないでください。かわりにXMLパーサーを使用して、文書の文字のエンコーディングが自動的に検出されるようにします。外部エンコーディング情報がないバイナリFileInputStreamの場合、パーサーは、バイト・オーダー・マークおよびXML文書のエンコーディング宣言に基づいて、文字のエンコーディングを自動的に判断します。$ORACLE_HOME/xdk/demo/java/parser/domにあるAutoDetectEncoding.javaデモのサンプル・コードを使用して、サポートされている任意のエンコーディングの任意の整形式文書を解析できます。

注意:

仕様のとおりに、文書内に適切なエンコーディング宣言を含めます。setEncoding()では、入力文書のエンコーディングを設定できません。setEncoding()oracle.xml.parser.v2.XMLDocumentと組み合せて使用し、出力用の適切なエンコーディングを設定します。

12.7.4.2 NCLOB列に格納されたXMLの文字の異常の防止

NCLOB列に格納されたXMLデータの文字の異常を防ぐには、getUnicodeStream()およびgetBinaryStream()メソッドを使用するか、データをパーサーに送信する前に印刷して、その文字に異常がないことを確認します。

8ビット・エンコーディングのUnicode (UTF-8)を使用してXMLをデータベースの各国語キャラクタ・ラージ・オブジェクト(NCLOB)列にロードし、XMLに2つのUTF-8マルチバイト・キャラクタが含まれているとします。

G(0xc2,0x82)otingen, Br(0xc3,0xbc)ck_W

次の処理を行うJavaストアド・ファンクションを作成します。

  1. デフォルトの接続オブジェクトを使用して、データベースに接続します。
  2. SELECT問合せを実行します。
  3. oracle.jdbc.OracleResultSetオブジェクトを取得します。
  4. OracleResultSet.getCLOB()メソッドを起動します。
  5. CLOBオブジェクトでgetAsciiStream()メソッドを起動します。
  6. 次のコードを実行してXMLをDOMオブジェクトに変換します。
    DOMParser parser = new DOMParser();
    parser.setPreserveWhitespace(true);
    parser.parse(istr);
    // istr getAsciiStream XMLDocument xmldoc = parser.getDocument();
    

プログラムは、文字(0xc20x82)が有効なUTF-8であっても、XMLに無効なUTF-8エンコーディングが含まれているということを示す例外をスローします。問題は、プログラムがOracleResultSet.getAsciiStream()メソッドを起動すると、文字に異常が発生する可能性があることです。この問題を解決するには、getAsciiStream()のかわりに、getUnicodeStream()およびgetBinaryStream()メソッドを起動します。この方法が機能しない場合は、DOMParser.parse(istr)を起動する際、文字がパーサーに送信される前に、文字が異常でないことを確認するために出力してみてください。

12.7.4.3 デフォルト以外のエンコーディングでのXMLファイルの作成

デフォルト文字エンコーディングでは使用できない文字を含むXMLファイルの作成時に利用できる、問題を回避するための方法について説明します。

UTF-8エンコーディングはXML文書には一般的ですが、UTF-8は、通常はJavaのデフォルトのファイル・エンコーディングではありません。デフォルトのファイル・エンコーディングを想定したJavaクラスをプログラムで使用すると、問題が発生する可能性があります。

たとえば、JavaクラスFileWriterは、実行時環境のデフォルトの文字エンコーディングに依存します。デフォルトの文字エンコーディングで使用できない文字が含まれるXMLファイルに書き込む際にFileWriterクラスを使用する場合、出力ファイルでは、解析エラーやデータの損失が発生する可能性があります。

このような問題を回避するために、$ORACLE_HOME/xdk/demo/java/parser/domI18nSafeXMLFileWritingSample.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(...);
12.7.4.4 文字列に格納されたXMLの解析

Stringに含まれているXML文書を解析するには、まず文字列をInputStreamまたはInputSourceオブジェクトに変換する必要があります。

例12-8では、XMLの文字列(xmlDocで参照)をバイト配列に変換し、バイト配列をByteArrwayInputStreamに変換して解析します。

PrintWriterStringWriterをラップすることで、前述のコードで作成したXMLDocumentオブジェクトを再び文字列に変換できます。次の例では、次の方法を示します。

例12-8で作成したXMLDocumentオブジェクトを再び文字列に変換するには、PrintWriterStringWriterをラップします。

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文書を文字列として作成し、それを解析する完全なプログラムです。

例12-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 get DOM tree
DOMParser.parse(bais);
XMLDocument doc = parser.getDocument();
12.7.4.5 アクセント付き文字を含むXML文書の解析

アクセント付き文字を含むXML文書の解析に関するヒントを示します。

例12-9に、アクセント付き文字(éなど)を含むXML文書の解析方法の1つを示します。

XMLファイルを解析しようとすると、パーサーによって、無効なUTF-8エンコーディングであるという例外がスローされることがあります。エンコーディングはUnicodeの文字番号表現をディスクに書き込むために使用されるスキームです。エンコーディングを明示的にUTF-8に設定した場合、またはエンコーディングを指定しない場合、パーサーはアクセント付き文字(127より大きいASCII値の文字)をUTF-8マルチバイト文字列の最初のバイトとして解析します。後続のバイトが有効なUTF-8文字列を構成していない場合、エラーが発生します。

このエラーは、XMLエディタがファイルをUTF-8エンコーディングを使用して保存していないことを意味します。エディタでファイルをISO-8859-1(西欧ASCII)エンコーディングで保存した可能性があります。次の要素をXML文書の最上部に追加しても、エディタはファイルを表すバイトをUTF-8エンコーディングを使用してディスクに書き込みません。

<?xml version="1.0" encoding="UTF-8"?>

1つの解決策として、アクセント付き文字は、XML文書内で&#xd9;のように16進または10進フォーマットで表すと読み取ることができます。この方法を使用しない場合は、XMLファイルの作成時に使用したキャラクタ・セットに基づいてエンコーディングを設定できます(ISO-8859-1など)。

例12-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")));
12.7.4.6 タグ名内の特殊文字の処理

XML要素名に含まれる特殊文字の処理に関するヒントを示します。

タグ(要素)名に特殊文字(&$#など)が含まれる場合、パーサーは無効な文字のエラーを表示します。

新規XML文書を作成している場合、無効なNameChar文字を含まないタグ名を選択します。たとえば、タグ名が会社名に基づき、ある会社の名前がA&Bの場合、無効なタグ<A&B>のかわりに、<A_B><AB>または<A_AND_B>を選択します。

データベース表などの外部データ・ソースからXMLを生成する場合、次のようになります。

  • XML 1.0は、この問題には対応していません。

  • XML 1.1では、データ型XMLTypeは、DBMS_XMLGENパッケージでsetConvertSpecialCharsおよびconvertファンクションを提供することで、この問題に対処しています。

    これらのファンクションを使用して、Structured Query Language (SQL)名とXML名の特殊文字の使用を制御できます。SQLからXMLに名前をマップするファンクションでは、無効なXML NameChar文字は_XHHHH_という形式(HHHHは無効な文字のUnicode値)でエスケープされます。たとえば、表名V$SESSIONはXMLの名前V_X0024_SESSIONにマップされます。

    無効な文字のエスケープは、名前を他の場所に再ロードできるようにシリアライズする方法を提供します。