この章の内容は次のとおりです。
Oracleでは、Java、C、C++およびPL/SQL用のXMLパーサーを提供しています。この章では、Java用のパーサーのみについて説明します。これらの各パーサーはスタンドアロンのXMLコンポーネントであり、アプリケーションで処理できるように、XML文書(場合によってはスタンドアロンのDTDまたはXML Schema)を解析します。この章に示すアプリケーションの例は、Javaで作成されています。
XML SchemaはXMLのW3C勧告であり、XML文書にデータ型の概念を導入し、DTDの構文をXMLに基づく構文に置き換えます。DTDまたはXML Schemaと照合してXML文書の構文を確認するプロセスを検証といいます。
外部のDTDを使用するには、XML文書にDTDへの参照を含めます。この参照がないと、パーサーが何に対して検証するのかを判断する方法がありません。参照を含めることは、外部DTDを指定するXMLの標準的な方法です。参照を含めない場合、XML文書にDTDを埋め込む必要があります。
図3-1に、XML Parser for Javaへの入力としてのXML文書を示します。DOMまたはSAXパーサーのインタフェースがXML文書を解析します。解析済のXMLは、追加処理のためにアプリケーションに転送されます。
XML Parser for Javaには、XSLスタイルシートを使用してXMLデータを変換するためのXSL Transformation(XSLT)Processorが統合されています。XSLT Processorを使用すると、XML文書をXMLからXML、XMLからHTMLなど、実質的にすべてのテキストベース形式の文書に変換できます。
スタイルシートを使用する場合、DOMまたはSAXインタフェースはXSLコマンドも解析および出力します。これらのコマンドは解析済のXMLとともにXSLT Processorに送信されます。XSLT Processorでは、選択したスタイルシートが適用され、変換済の(新しい)XML文書が出力されます。図3-1に、XML Parser for Javaの概要を簡単に示します。
XML Parser for JavaのプロセッサはXML文書を読み取り、そのコンテンツや構造へのアクセスを提供します。XMLプロセッサは、他のモジュール(アプリケーション)のかわりにその作業を実行します。図3-2に、この解析プロセスを示します。
|
関連資料:
|
XML Parser for Javaは、XML名前空間もサポートします。名前空間は、XML文書内にある要素タイプ(タグ)間または属性間の名前の競合を解決または回避するメカニズムです。
このメカニズムでは、汎用の名前空間の要素タイプと属性名が提供されます。このようなタグは、次のUniform Resource Identifiers(URI)によって修飾されます。
<oracle:EMP xmlns:oracle="http://www.oracle.com/xml"/>
たとえば、名前空間を使用すると、オラクル社の<EMP>データ要素を、他企業の<EMP>データ要素の定義と区別して特定できます。これにより、アプリケーションは処理する要素と属性をさらに簡単に特定できます。
XML Parser for Javaは、汎用の要素タイプおよび属性名と、ローカルの非修飾の要素タイプおよび属性名を解析できます。
|
関連資料:
|
検証では、属性名や要素タグが有効であるかどうか、ネストした要素が所定の位置にあるかどうかなどを確認します。
<!DOCTYPE>宣言で定義されたDTDファイルは、入力XML文書の位置に相対的である必要があります。相対的ではない場合、setBaseURL(url)ファンクションを使用してベースURLを設定し、入力がInputStreamからの場合にDTDの相対アドレスを解決する必要があります。
InputStreamを解析している場合、パーサーではInputStreamの送信元を認識しないため、現在のファイルと同じディレクトリ内にDTDを見つけることができません。これを解決するには、DOMParser()でsetBaseURL()を使用して、パーサーにURLの情報の一部を与え、DTDを取得するときに残り情報を導出できるようにします。
XML文書は、エンティティと呼ばれる記憶域単位で構成されます。エンティティには、解析対象データまたは解析対象外データが含まれます。解析対象データは文字で構成され、文字の一部は文字データとマークアップで形成されます。
マークアップは、文書の記憶域のレイアウトや論理構造の記述をエンコードします。XMLは、記憶域のレイアウトや論理構造を制約するメカニズムを提供します。
解析メソッドsetValidationMode(mode)は、表3-1に示すモード値でXMLを解析します。
表3-1 XML Parser for Javaの検証モード
| モードの名前 | Javaでのモード値 | 説明 |
|---|---|---|
|
非検証モード |
|
XMLが整形式であることを確認し、DOM APIで操作できるオブジェクトのツリーにデータを解析します。 |
|
|
XMLが整形式であることを確認し、DTDがある場合はXMLデータがDTDに対して妥当であるかどうかを検証します。 |
|
|
|
DTDまたはXML Schema(存在する場合)に従って、入力XML文書のすべてまたは一部を検証します。DTDまたはXMLスキーマが存在しない場合、モードは非検証モードに設定されます。このモードの場合、スキーマ・バリデータはスキーマを見つけて構築し、schemaLocationおよびnoNamespaceSchemaLocation属性に基づいてインスタンス・ドキュメント全体、またはその一部を検証します。ディレクトリ |
|
|
|
XML文書は、その文書に対して指定されたXML Schemaに従って検証されます。 |
|
|
LAX検証 |
|
バリデータは、スキーマ定義が検出されなくなるまで、インスタンス・ドキュメントの一部またはすべての検証を試行します。定義が検出されない場合も、エラーは発生しません。これはschemaディレクトリのサンプル |
|
厳密な検証 |
|
バリデータはインスタンス・ドキュメント全体の検証を試行します。スキーマ定義が検出されない場合またはインスタンスが定義に準拠しない場合は、エラーが発生します。 |
|
説明を参照してください。 |
DTDが使用可能な場合、モード値は |
スキーマ自体を構築するバリデータの他に、XSDBuilderを使用してスキーマを構築し、setXMLSchema()メソッドを使用してこのスキーマをバリデータに設定できます。コード例のXSDSetSchema.javaを参照してください。setXMLSchema()メソッドを使用することで、検証モードはSCHEMA_STRICT_VALIDATIONに自動的に設定され、schemaLocationおよびnoNamespaceSchemaLocation属性は無視されます。検証モードをSCHEMA_LAX_VALIDATIONに変更することもできます。
次にDTDの使用について説明します。この項の内容は次のとおりです。
DTDキャッシュ機能はオプションであり、自動的に有効になりません。
XML Parser for Javaでは、setDoctype()ファンクションによってDTDキャッシュの検証機能および非検証機能が提供されます。このファンクションを使用してDTDを設定した後、XMLParserではこのDTDがキャッシュして追加の解析を実行します。
アプリケーションで同じDTDを使用して複数のXML文書を解析する必要がある場合、最初のXML文書を解析した後、パーサーからそのDTDを取得して次のように戻すことができます。
dtd = parser.getDoctype(); parser.setDoctype(dtd);
パーサーではこのDTDをキャッシュして、次のXML文書の解析に使用します。
キャッシュしたDTDオブジェクトが次の構文による検証目的でのみ使用する場合、DOMParser.USE_DTD_ONLY_FOR_VALIDATION属性を設定します。
parser.setAttribute(DOMParser.USE_DTD_ONLY_FOR_VALIDATION,Boolean.TRUE);
DTDオブジェクトが検証に使用されない場合、XMLパーサーはDTDオブジェクトをコピーして、結果のDOMツリーに追加します。
DTDを設定するメソッドはsetDoctype()です。次に例を示します。
// Test using InputSource parser = new DOMParser(); parser.setErrorStream(System.out); parser.showWarnings(true); FileReader r = new FileReader(args[0]); InputSource inSource = new InputSource(r); inSource.setSystemId(createURL(args[0]).toString()); parser.parseDTD(inSource, args[1]); dtd = (DTD)parser.getDoctype(); r = new FileReader(args[2]); inSource = new InputSource(r); inSource.setSystemId(createURL(args[2]).toString()); // ******************** parser.setDoctype(dtd); // ******************** parser.setValidationMode(DTD_VALIDATION); parser.parse(inSource);
doc = (XMLDocument)parser.getDocument(); doc.print(new PrintWriter(System.out));
外部DTDを認識するために、XML Parser for JavaにはsetBaseURL()メソッドがあります。
DTDをリダイレクトするにはresolveEntity()を使用します。
DOMパーサーのparseDTD()メソッドを使用して外部DTDを解析します。
getDoctype()をコールして、oracle.xml.parser.v2.DTDのインスタンスを取得します。
プログラムでDTDを設定する文書では、setDoctype(yourDTD)コールを使用します。この方法を使用して、製品のJARファイル以外からDTDを読み取ります。
パーサーはベースURLメソッド(setBaseURL())をサポートしますが、このメソッドはすべてのDTDが公開されている場所を指すのみです。
次の手順を実行します。
DTDをInputStreamとしてロードします。
InputStream is = YourClass.class.getResourceAsStream("/foo/bar/your.dtd");
このコードによって、DTDが指定されているCLASSPATH上の最初の相対位置にある./foo/bar/your.dtdが開かれます。JARがCLASSPATHにある場合は、JAR以外の場所からも開かれます。
DTDを解析します。
DOMParser d = new DOMParser(); d.parseDTD(is, "rootelementname"); d.setDoctype(d.getDoctype());
ドキュメントを解析します。
d.parse("yourdoc");
DOM APIを使用してDOMツリーが作成されている間は検証は行われません。そのためドキュメントにDTDを設定しても、作成されるDOMツリーの検証には役立ちません。XMLファイルを検証する唯一の方法は、DOMパーサーまたはSAXパーサーを使用してXML文書を解析することです。
parseDTD()メソッドを使用すると、DTDファイルを個別に解析し、DTDオブジェクトを取得できます。次に、このタスクを実行するためのサンプル・コードを示します。
DOMParser domparser = new DOMParser(); domparser.setValidationMode(DTD_VALIDATION); /* parse the DTD file */ domparser.parseDTD(new FileReader(dtdfile)); DTD dtd = domparser.getDoctype();
XMLは本質的に大文字と小文字を区別するため、パーサーではこれに準拠して大文字と小文字が区別されます。非検証モードで実行する場合、整形式であるかどうかのみがカウントされます。ただし、<test></Test>は、非検証モードでもエラーを通知します。
DOM APIを使用して新しいDOCUMENT_TYPE_NODEオブジェクトを作成する方法はありません。DTDオブジェクトを取得するには、DOMパーサーでDTDファイルまたはXMLファイルを解析して、getDocType()メソッドを使用します。
次の文ではDTDオブジェクトは作成されません。この文ではタイプがDOCUMENT_TYPE_NODEに設定されたXMLNodeオブジェクトが作成されますが、この方法は実際には使用されません。appendChildが(タイプに基づいて)DTDオブジェクトを予測するため、ClassCastExceptionが発生します。
appendChild(New XMLNode("test",Node.DOCUMENT_TYPE_NODE));
XMLを解析するAPIは次の2種類があります。
DOM API(ツリーベース)
SAX API(イベントベース)
次の単純なXML文書について考えてみます。
<?xml version="1.0"?>
<EMPLIST>
<EMP>
<ENAME>MARY</ENAME>
</EMP>
<EMP>
<ENAME>SCOTT</ENAME>
</EMP>
</EMPLIST>
ツリーベースAPI(DOMなど)は、メモリー内にXML文書のツリー表現を構築します。DOMは、ツリーをナビゲートおよび処理するためのアプリケーションのクラスおよびメソッドを提供します。
通常、要素の並替え、要素や属性の追加または削除、要素名の変更など、XMLツリーの構造的な操作に最も役立ちます。たとえば、直前のXML文書の場合、図3-3に示すように、DOMではメモリー内にツリー構造を作成します。
イベントベースAPI(SAXなど)は、コールを使用して解析イベントをアプリケーションに通知します。Javaアプリケーションでは、カスタマイズされたイベント・ハンドラを介してこれらのイベントを処理します。イベントには、要素や文字の開始および終了などがあります。
ツリーベースAPIとは異なり、イベントベースAPIでは、通常メモリー内にXML文書のツリー表現は構築されません。そのため、一般的にSAXは、イベント間でXMLツリーの操作(検索操作など)が必要ではないアプリケーションの場合に便利です。図3-3に示すように、前述のXML文書は一連の線形イベントになります。
DOM APIおよびSAX APIを使用のガイドラインを示します。
ランダム・アクセスを使用する必要がある場合、DOM APIを使用します。
XSL変換を実行している場合、DOMを使用します。
XPathをコールしている場合、DOMを使用します。SAXはXPathをサポートしません。
ツリーの反復を使用する場合やドキュメント・ツリー全体を移動する必要がある場合、DOMを使用します。
DOMツリーの構築をカスタマイズ: org.w3c.dom.Is.DOMBuilderFilter。
検証が必要ではない場合、外部DTDの解析を回避: DOMParser.set.Attribute(DOMParsser.STANDALONE, Boolean.TRUE);。
必要ではない場合、DOMにDTDオブジェクトを含めないようにする: DOMParser.setAttribute(DOMParser.USE_DTD_ONLY_FOR_VALIDATION, Boolean.TRUE);。
DTD検証に対してDTDキャッシュ機能を使用: DOMParser.setDoctype(dtd);。
DOM 3.0 Load and Saveを使用してDOMを非同期に構築: DOMImplementationLS.MODE_ASYNCHRONOUS。
統合されたDOM APIは、XMLType列とXML文書をサポートします。
DOMインタフェースを使用する場合、パイプ・サイズが小さくなるように、XMLでは要素よりも多くの属性を使用します。
ほとんどのデータがストリーミング形式である場合、SAX APIを使用します。
メモリーを節約する場合、SAXを使用します。DOMの方が多くのメモリーを消費します。
データベースからのXML文書の取得を高速化するには、DOMではなくSAXインタフェースを使用します。索引列のCOUNT(*)を必ず選択します(索引の選択性が高いほど有効です)。この場合、オプティマイザは、全表スキャンのかわりに、数回の索引ブロック入力および出力のみでCOUNT問合せを実行できます。
SAX 2.0を使用します。SAX 1.0は使用できなくなりました。
SAXには印刷書式、XML宣言、CDATA、DTDの出力オプションがあります。
SAX処理をマルチタスク化して、スループットを向上します(マルチハンドラを使用して、コールバックで複数の処理を可能にします)。oracle.xml.parser.V2.XMLMultiHandlerは、SAXを解析するたびに複数のハンドラを登録します。
oracle.xml.parser.V2.XMLSAXSerializerは、組込みXMLシリアライザを使用して、出力の作成を簡略化します。
XML Compressorは、XML文書のバイナリでの圧縮をサポートします。圧縮は、XMLタグのトークン化に基づいています。これは、すべてのXML文書にはタグの繰返しがあるため、それらのタグをトークン化すると、データが大幅に圧縮されることを前提としています。そのため実行される圧縮は、入力文書のタイプに依存します。タグの数が多く、テキスト・コンテンツが少ないほど、圧縮率が向上します。
圧縮の目的は、DOMツリーの構造情報および階層情報を失うことなく、XML文書のサイズを小さくすることです。圧縮したストリームには、バイナリ形式からDOMツリーを作成するためのすべての有効な情報が含まれます。また、SAXイベントから圧縮ストリームを生成することもできます。
XML Parser for Javaも、XML文書を圧縮できます。圧縮機能を使用すると、メモリー内のDOMツリー、またはXML文書から生成されたSAXイベントが圧縮され、圧縮したバイナリ出力が生成されます。DOMおよびSAXから生成された圧縮ストリームには互換性があるため、SAXから生成された圧縮ストリームを使用してDOMツリーを生成したり、DOMから生成された圧縮ストリームを使用してSAXイベントを生成したりできます。
通常、XML文書と同様に、圧縮したXMLデータ出力はデータベースにBLOB(バイナリ・ラージ・オブジェクト)として格納できます。
表3-2「XML Parser for Javaのサンプル・プログラム」に、圧縮機能を例示するサンプル・プログラムを示します。
XML文書は、メモリー内DOMツリーのシリアライズによってバイナリ・ストリームに圧縮されます。大規模なXML文書を解析して、対応するDOMツリーをメモリー内に作成する場合、メモリー要件を満たすことが難しいため、パフォーマンスが低下する可能性があります。XML文書はバイナリ・ストリームに圧縮されて、メモリー内DOMツリーに格納されます。この文書は、圧縮したストリームに格納されたXMLデータを検証せずに後でDOMツリーに拡張できます。
圧縮したストリームはシリアライズされたストリームとして処理できますが、ストリーム内の情報は、Javaのデフォルトのシリアライズによって実装される圧縮よりも厳密に制御および管理されます。
XMLの圧縮ストリームには次の2種類があります。
DOMベース圧縮: 解析済XML文書に対応するメモリー内DOMツリーがシリアライズされ、圧縮したXML出力ストリームが生成されます。このシリアライズされたストリームは、再度読み取られると、DOMツリーを再生成します。
SAXベース圧縮: SAXパーサーを使用してXMLファイルを解析する際に、圧縮したストリームが生成されます。SAXパーサーによって生成されたSAXイベントは、SAX圧縮ユーティリティによって処理されます。SAX圧縮ユーティリティは、SAXイベントを処理して圧縮したバイナリ・ストリームを生成します。バイナリ・ストリームが再度読み取られると、SAXイベントが生成されます。
|
注意: Oracle Textは、圧縮されたXML文書を検索できません。解凍によりパフォーマンスが低下します。クライアントとサーバー間でファイルを転送している場合は、HTTP圧縮の方が簡単です。圧縮はXDK Javaコンポーネントでのみサポートされます。 |
demo/java/parserディレクトリには、XML Parser for Javaの使用方法を示すXMLサンプル・アプリケーションがあります。次に、サブディレクトリ(common、comp、dom、jaxp、saxおよびxslt)にあるサンプルJavaファイルを示します。
図3-2 XML Parser for Javaのサンプル・プログラム
| サンプル・プログラム | 用途 |
|---|---|
|
|
XSL APIを使用するサンプル・アプリケーション |
|
|
DOM APIを使用するサンプル・アプリケーション |
|
|
DOM APIへの名前空間による拡張を使用するサンプル・アプリケーション |
|
|
DOMレベル2.0 APIを使用するサンプル・アプリケーション |
|
|
DOM範囲APIを使用するサンプル・アプリケーション |
|
|
DOM Event APIを使用するサンプル・アプリケーション |
|
|
DOM Iterator APIを使用するサンプル・アプリケーション |
|
|
DOM TreeWalker APIを使用するサンプル・アプリケーション |
|
|
SAX APIを使用するサンプル・アプリケーション |
|
|
SAX APIへの名前空間による拡張を使用するサンプル・アプリケーション |
|
|
SAX 2.0を使用するサンプル・アプリケーション |
|
|
|
|
|
DOMツリーを圧縮するサンプル・アプリケーション |
|
|
圧縮したストリームからDOMを再度読み取るサンプル |
|
|
SAXパーサーからのSAX出力を圧縮するサンプル・アプリケーション |
|
|
圧縮したストリームからSAXイベントを再生成するサンプル・アプリケーション |
|
|
JAXP 1.1 APIを使用するサンプル |
Tokenizerアプリケーションは、XMLTokenインタフェースを実装します。このインタフェースは、setTokenHandler()メソッドを使用して登録する必要があります。XMLTokenのリクエストは、setToken()メソッドを使用して登録します。トークン化実行中、パーサーは、ドキュメントを検証せず、内部または外部のユーティリティの追加または読取りも行いません。
サンプル・プログラムを実行するには、次の手順を実行します。
xdk/demo/javaディレクトリのmake(UNIXの場合)またはMake.bat(Windowsの場合)を使用して、.classファイルを生成します。
xmlparserv2.jarおよび現在のディレクトリをCLASSPATHに追加します。
次の手順を順番に実行する必要はありません(解凍を除く)。
各ディレクトリでDOM APIおよびSAX APIのサンプル・プログラムを実行します。
java classname sample_xml_file
そのディレクトリでXSL APIのサンプル・プログラムを実行します。
java XSLSample sample_xsl_file sample_xml_file
そのディレクトリでTokenizer APIのサンプル・プログラムを実行します。
java Tokenizer sample_xml_file token_string
そのディレクトリでDOMツリーを圧縮するサンプル・プログラムを実行します。
java DOMCompression sample.dat
圧縮した出力は、xml.serというファイルに生成されます。
最後の手順を終えたら、サンプル・プログラムを実行して、圧縮ストリームからDOMツリーを構築します。
java DOMDeCompression xml.ser
そのディレクトリでSAXイベントを圧縮するサンプル・プログラムを実行します。
java SAXCompression sample.dat
最後の手順を終えたら、圧縮ストリームからSAXイベントを再生成するサンプル・プログラムを実行します。
java SAXDeCompression xml.ser
そのディレクトリでJAXP 1.1 APIのサンプル・プログラムを実行します。
java JAXPExamples
XML文書ファイルおよびスタイルシートが、JAXPExamples.javaプログラムの内部で指定されます。Content Handlerは、JavaファイルoraContentHandler.javaの内部にあります。
DOMベースのパーサー・アプリケーションを作成するには、次のクラスを使用できます。
DOMNamespaceクラス
DOMParserクラス
XMLParserクラス
DOMParserはXMLParserを拡張するため、XMLParserのすべてのメソッドはDOMParserで使用できます。図3-4「XML Parser for Java: DOMParser()」に、DOMParserクラスを使用したコードを作成する際に必要とされる主な手順を示します。
アプリケーションによっては、XML文書を検証する必要はありません。この場合、DTDは不要です。
新しいDOMParser()をコールします。このオブジェクトで使用するメソッドは次のとおりです。
setValidateMode()
setPreserveWhiteSpace()
setDoctype()
setBaseURL()
showWarnings()
DOMParser()の結果は、XML入力とともにXMLParser.parse()に渡されます。XML入力は、ファイル、文字列バッファまたはURLのいずれかです。
XMLParser.getDocument()メソッドを使用します。
オプションで、次に示すその他のDOMメソッドを適用できます。
print()
DOMNamespace()メソッド
パーサーはDOMツリーのXML(解析済)文書を出力します。
DOM APIがDOMツリーの構築を終えると、オプションでDOMParser.reset()を使用して、内部データ構造を削除します。
入力XML文書を検証する必要がある場合、DTDを使用します。
新しいDOMParser()をコールします。このオブジェクトに適用するメソッドは次のとおりです。
setValidateMode()
setPreserveWhiteSpace()
setDocType()
setBaseURL()
showWarnings()
DOMParser()の結果は、DTD入力とともにXMLParser.parseDTD()メソッドに渡されます。
XMLParser.getDocumentType()メソッドは、新しいDOMParser()に結果のDTDオブジェクトを送信し、DTDが適用されるまでそのプロセスを続行します。
次に示すコメントは、この項の直後にある例1: DOMSample.javaに関するものです。
新しいDOMParser()インスタンスを宣言します。
DOMParser parser = new DOMParser();
XML入力は入力ファイル名から生成されたURLです。
URL url = DemoUtil.createURL(argv[0]);
DOMParserクラスには、使用可能な複数のメソッドがあります。この例で使用されているメソッドは次のとおりです。
parser.setErrorStream(System.err); parser.setValidationMode(DTD_VALIDATION); parser.showWarnings(true);
入力ドキュメントを解析します。
parser.parse(url);
DOMツリー・ドキュメントを取得します。
XMLDocument doc = parser.getDocument();
このプログラムでは、nodeクラス・メソッドを適用します。
getElementsByTagName()
getTagName()
getAttributes()
getNodeName()
getNodeValue()
各要素の属性が出力されます。
|
注意: DOMSample.javaではDTD入力は示されていません。
|
この例では、前述の手順を使用するJavaコードを示します。
/* Copyright (c) Oracle Corporation 2000, 2001. All Rights Reserved. */
/**
* DESCRIPTION
* This file demonstates a simple use of the parser and DOM API.
* The XML file that is given to the application is parsed and the
* elements and attributes in the document are printed.
* The use of setting the parser options is demonstrated.
*/
import java.net.URL;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.NamedNodeMap;
import oracle.xml.parser.v2.DOMParser;
import oracle.xml.parser.v2.XMLDocument;
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);
}
// Get an instance of the parser
DOMParser parser = new DOMParser();
// Generate a URL from the filename.
URL url = DemoUtil.createURL(argv[0]);
// Set various parser options: validation on,
// warnings shown, error stream set to stderr.
parser.setErrorStream(System.err);
parser.setValidationMode(DOMParser.DTD_VALIDATION);
parser.showWarnings(true);
// Parse the document.
parser.parse(url);
// Obtain the document.
XMLDocument doc = parser.getDocument();
// Print document elements
System.out.print("The elements are: ");
printElements(doc);
// Print document element attributes
System.out.println("The attributes of each element are: ");
printElementAttributes(doc);
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
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();
}
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();
}
}
}
図3-3に、DOMインタフェースを使用したXML文書の解析の主なプロセスを示します。次の例では、DOMNamespaceクラスの使用方法を示します。
メソッドの使用ガイドについては、このソース・コードのコメントを参照してください。プログラムは次のコメントで開始します。
/** * DESCRIPTION * This file demonstates a simple use of the parser and Namespace * extensions to the DOM APIs. * The XML file that is given to the application is parsed and the * elements and attributes in the document are printed. */
NSNameインタフェースのXMLElementで使用されるメソッドは、要素や属性名に名前空間サポートを提供します。
getQualifiedName()は修飾名を戻します。
getLocalName()はローカル名を戻します。
getNamespace()は名前の解決済名前空間を戻します。
getExpandedName()は解決済完全名を戻します。
次に、これらのメソッドを後でコードで使用する方法を示します。
// Use the methods getQualifiedName(), getLocalName(), getNamespace()
// and getExpandedName() in NSName interface to get Namespace
// information.
qName = nsElement.getQualifiedName();
System.out.println(" ELEMENT Qualified Name:" + qName);
localName = nsElement.getLocalName();
System.out.println(" ELEMENT Local Name :" + localName);
nsName = nsElement.getNamespace();
System.out.println(" ELEMENT Namespace :" + nsName);
expName = nsElement.getExpandedName();
System.out.println(" ELEMENT Expanded Name :" + expName);
}
属性の場合、getNodeValue()メソッドは、タイプに応じて、このノードの値を戻します。次に、このプログラムの後半の抜粋部分を示します。
nnm = e.getAttributes();
if (nnm != null)
{
for (i=0; i < nnm.getLength(); i++)
{
nsAttr = (XMLAttr) nnm.item(i);
// Use the methods getExpandedName(), getQualifiedName(),
// getNodeValue() in NSName
// interface to get Namespace information.
attrname = nsAttr.getExpandedName();
attrqname = nsAttr.getQualifiedName();
attrval = nsAttr.getNodeValue();
DOMNameSpace.javaではDTD入力は示されていません。
アプリケーションはSAXハンドラを登録して、様々なパーサー・イベントの通知を受信できます。XMLReaderは、XMLパーサーのSAX2ドライバが実装する必要のあるインタフェースです。このインタフェースを使用すると、アプリケーションはパーサーの機能やプロパティの設定および問合せを行い、イベント・ハンドラを登録してドキュメントを処理して、ドキュメントの解析を開始できます。
すべてのSAXインタフェースは、同期であることが前提です。そのため、解析メソッドは解析が完了するまで結果を戻しません。リーダーは、次のイベントを通知する前にイベント・ハンドラのコールバックが結果を戻すまで待機する必要があります。
このインタフェースは、(現在使用されなくなった)SAX 1.0パーサーのインタフェースにかわるものです。XMLReaderインタフェースには、古いパーサーのインタフェースよりも優れた2つの重要な拡張機能があります。
機能やプロパティの問合せおよび設定を行う標準的な方法が追加されています。
高水準の多くのXML標準に必要な名前空間サポートが追加されています。
表3-3に、SAXParserメソッドを示します。
表3-3 SAXParserメソッド
| メソッド | 説明 |
|---|---|
|
|
現在のコンテンツ・ハンドラを戻します。 |
|
|
現在のDTDハンドラを戻します。 |
|
|
現在のエンティティ・リゾルバを戻します。 |
|
|
現在のエラー・ハンドラを戻します。 |
|
|
機能の値を検索します。 |
|
|
プロパティの値を検索します。 |
|
|
アプリケーションがコンテンツ・イベント・ハンドラを登録できます。 |
|
|
SAX2.0の時点で使用されなくなりました。 |
|
|
アプリケーションがDTDイベント・ハンドラを登録できます。 |
|
|
アプリケーションがエンティティ・リゾルバを登録できます。 |
|
|
アプリケーションがエラー・イベント・ハンドラを登録できます。 |
|
|
機能の状態を設定します。 |
|
|
プロパティの値を設定します。 |
図3-5に、SAXParserクラスを使用したコードを作成するための主な手順を示します。
パーサーの新しいハンドラを作成します。
SAXSample sample = new SAXSample();
新しいSAXParser()オブジェクトを宣言します。表3-3に、すべての使用可能なメソッドを示します。
Parser parser = new SAXParser;
検証モードをDTD_VALIDATIONに設定します。
入力ファイルをURLに変換して解析します。
parser.parse(DemoUtil.createURL(argv[0].toString());
解析が完了すると解析メソッドが戻ります。その間プロセスは、次のイベントを通知する前にイベント・ハンドラのコールバックが結果を戻すまで待機します。
解析されたXML文書は、このアプリケーションによる出力に使用できます。使用されるインタフェースは次のとおりです。
DocumentHandler
EntityResolver
DTDHandler
ErrorHandler
この例では、SAXParserクラスと複数のハンドラ・インタフェースの使用方法を示します。メソッドの使用ガイドについては、このソース・コードのコメントを参照してください。
SAXは、イベントベースのXML解析用の標準インタフェースです。パーサーは、setDocumentLocator()およびstartDocument()などのコールバック関数によってイベントの解析を直接通知します。このアプリケーションではハンドラを使用して、様々なイベントを処理します。
/* Copyright (c) Oracle Corporation 2000, 2001. All Rights Reserved. */
/**
* DESCRIPTION
* This file demonstates a simple use of the parser and SAX API.
* The XML file that is given to the application is parsed and
* prints out some information about the contents of this file.
*/
import java.net.URL;
import org.xml.sax.Parser;
import org.xml.sax.Locator;
import org.xml.sax.AttributeList;
import org.xml.sax.HandlerBase;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import oracle.xml.parser.v2.SAXParser;
public class SAXSample extends HandlerBase
{
// Store the locator
Locator locator;
static public void main(String[] argv)
{
try
{
if (argv.length != 1)
{
// Must pass in the name of the XML file.
System.err.println("Usage: SAXSample filename");
System.exit(1);
}
// Create a new handler for the parser
SAXSample sample = new SAXSample();
// Get an instance of the parser
Parser parser = new SAXParser();
// set validation mode
((SAXParser)parser).setValidationMode(SAXParser.DTD_VALIDATION);
// Set Handlers in the parser
parser.setDocumentHandler(sample);
parser.setEntityResolver(sample);
parser.setDTDHandler(sample);
parser.setErrorHandler(sample);
// Convert file to URL and parse
try
{
parser.parse(DemoUtil.createURL(argv[0]).toString());
}
catch (SAXParseException e)
{
System.out.println(e.getMessage());
}
catch (SAXException e)
{
System.out.println(e.getMessage());
}
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
//////////////////////////////////////////////////////////////////////
// Sample implementation of DocumentHandler interface.
//////////////////////////////////////////////////////////////////////
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);
}
}
public void endElement(String name) throws SAXException
{
System.out.println("EndElement:"+name);
}
public void characters(char[] cbuf, int start, int len)
{
System.out.print("Characters:");
System.out.println(new String(cbuf,start,len));
}
public void ignorableWhitespace(char[] cbuf, int start, int len)
{
System.out.println("IgnorableWhiteSpace");
}
public void processingInstruction(String target, String data)
throws SAXException
{
System.out.println("ProcessingInstruction:"+target+" "+data);
}
//////////////////////////////////////////////////////////////////////
// Sample implementation of the EntityResolver interface.
//////////////////////////////////////////////////////////////////////
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;
}
//////////////////////////////////////////////////////////////////////
// Sample implementation of the DTDHandler interface.
//////////////////////////////////////////////////////////////////////
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);
}
//////////////////////////////////////////////////////////////////////
// Sample implementation of the ErrorHandler interface.
//////////////////////////////////////////////////////////////////////
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());
}
}
SAX APIの使用の詳細は、このソース・コードのコメントを参照してください。
/* Copyright (c) Oracle Corporation 2000, 2001. All Rights Reserved. */
/**
* DESCRIPTION
* This file demonstrates a simple use of the Namespace extensions to
* the SAX 1.0 APIs.
*/
import java.net.URL;
import org.xml.sax.HandlerBase;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
// Extensions to the SAX Interfaces for Namespace support.
import oracle.xml.parser.v2.XMLDocumentHandler;
import oracle.xml.parser.v2.DefaultXMLDocumentHandler;
import oracle.xml.parser.v2.NSName;
import oracle.xml.parser.v2.SAXAttrList;
import oracle.xml.parser.v2.SAXParser;
public class SAXNamespace {
static public void main(String[] args) {
String fileName;
//Get the file name
if (args.length == 0)
{
System.err.println("No file Specified!!!");
System.err.println("USAGE: java SAXNamespace <filename>");
return;
}
else
{
fileName = args[0];
}
try {
// Create handlers for the parser
// Use the XMLDocumentHandler interface for namespace support
// instead of org.xml.sax.DocumentHandler
XMLDocumentHandler xmlDocHandler = new XMLDocumentHandlerImpl();
// For all the other interface use the default provided by
// Handler base
HandlerBase defHandler = new HandlerBase();
// Get an instance of the parser
SAXParser parser = new SAXParser();
// set validation mode
((SAXParser)parser).setValidationMode(SAXParser.DTD_VALIDATION);
// Set Handlers in the parser
// Set the DocumentHandler to XMLDocumentHandler
parser.setDocumentHandler(xmlDocHandler);
// Set the other Handler to the defHandler
parser.setErrorHandler(defHandler);
parser.setEntityResolver(defHandler);
parser.setDTDHandler(defHandler);
try
{
parser.parse(DemoUtil.createURL(fileName).toString());
}
catch (SAXParseException e)
{
System.err.println(args[0] + ": " + e.getMessage());
}
catch (SAXException e)
{
System.err.println(args[0] + ": " + e.getMessage());
}
}
catch (Exception e)
{
System.err.println(e.toString());
}
}
}
/***********************************************************************
Implementation of XMLDocumentHandler interface. Only the new
startElement and endElement interfaces are implemented here. All other
interfaces are implemented in the class HandlerBase.
**********************************************************************/
class XMLDocumentHandlerImpl extends DefaultXMLDocumentHandler
{
public void XMLDocumentHandlerImpl()
{
}
public void startElement(NSName name, SAXAttrList atts) throws SAXException
{
// Use the methods getQualifiedName(), getLocalName(), getNamespace()
// and getExpandedName() in NSName interface to get Namespace
// information.
String qName;
String localName;
String nsName;
String expName;
qName = name.getQualifiedName();
System.out.println("ELEMENT Qualified Name:" + qName);
localName = name.getLocalName();
System.out.println("ELEMENT Local Name :" + localName);
nsName = name.getNamespace();
System.out.println("ELEMENT Namespace :" + nsName);
expName = name.getExpandedName();
System.out.println("ELEMENT Expanded Name :" + expName);
for (int i=0; i<atts.getLength(); i++)
{
// Use the methods getQualifiedName(), getLocalName(), getNamespace()
// and getExpandedName() in SAXAttrList interface to get Namespace
// information.
qName = atts.getQualifiedName(i);
localName = atts.getLocalName(i);
nsName = atts.getNamespace(i);
expName = atts.getExpandedName(i);
System.out.println(" ATTRIBUTE Qualified Name :" + qName);
System.out.println(" ATTRIBUTE Local Name :" + localName);
System.out.println(" ATTRIBUTE Namespace :" + nsName);
System.out.println(" ATTRIBUTE Expanded Name :" + expName);
// 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(NSName name) throws SAXException
{
// Use the methods getQualifiedName(), getLocalName(), getNamespace()
// and getExpandedName() in NSName interface to get Namespace
// information.
String expName = name.getExpandedName();
System.out.println("ELEMENT Expanded Name :" + expName);
}
}
XML Parser for Javaの使用に役立ついくつかのヒントを示します。この項の内容は次のとおりです。
DOM APIおよびSAX APIに関する追加情報を示します。
パーサーを使用して特定のタグ内の要素数を取得するには、指定のタグ名ですべての子孫要素のノード・リストを戻すgetElementsByTagName()メソッドを使用できます。そのノード・リストの要素数を調べて、特定のタグ内の要素数を確認できます。
ノードのタイプを説明する表に関するDOM仕様を確認すると、要素ノードを作成する場合に、そのノード値がnullになるため、ノードを設定できないことがわかります。ただし、テキスト・ノードを作成して、要素ノードに追加できます。その後、テキスト・ノードに値を追加できます。
DOM APIを使用してツリーを全検索できます。また、XPath構文を取るselectNodes()メソッドを使用してXML文書内をナビゲートできます。selectNodes()は、oracle.xml.parser.v2.XMLNodeの一部です。
次に、DOMツリー内を移動せずに要素の最初の子ノードの値を効率的に取得する方法を示します。ツリー全体が必要ではない場合、SAXインタフェースを使用して必要なデータを戻します。SAXはイベント・ドリブンであるため、ドキュメント全体を解析する必要はありません。
selectNodes()メソッドは、XMLElementノードおよびXMLDocumentノードで使用されます。このメソッドを使用して、XSLが許可する選択パターンに基づいてツリーまたはサブツリーからコンテンツを抽出します。selectNodes()のオプションの2つ目のパラメータを使用して、名前空間の接頭辞を解決します(つまり、接頭辞付きの展開された名前空間URLを戻します)。XMLElementはNSResolverを実装するため、2つ目のパラメータとして送信できます。XMLElementは、入力ドキュメントに基づいて接頭辞を解決します。名前空間の定義をオーバーライドする必要がある場合、NSResolverインタフェースを使用できます。次のサンプル・コードではselectNodesを使用します。
public class SelectNodesTest {
public static void main(String[] args) throws Exception {
String pattern = "/family/member/text()";
String file = args[0];
if (args.length == 2)
pattern = args[1];
DOMParser dp = new DOMParser();
dp.parse(createURL(file)); // Include createURL from DOMSample
XMLDocument xd = dp.getDocument();
XMLElement e = (XMLElement) xd.getDocumentElement();
NodeList nl = e.selectNodes(pattern, e);
for (int i = 0; i < nl.getLength(); i++) {
System.out.println(nl.item(i).getNodeValue());
}
}
}
> java SelectNodesTest family.xml
Sarah
Bob
Joanne
Jim
> java SelectNodesTest family.xml //member/@memberid
m1
m2
m3
m4
簡単な変数に含まれる情報から開始するXML文書の生成の例を示します。たとえばクライアントがJavaフォームに入力し、XML文書を取得する場合などです。
Javaに次の2つの変数があるとします。
String firstname = "Gianfranco"; String lastname = "Pietraforte";
次に、この情報をXML文書に挿入する2つの方法を示します。
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("first");
e1.appendChild(e2);
Text t = xmldoc.createText(firstname);
e2.appendChild(t);
DOMの場合、<name>macy</name>は実際に、値がmacyである子ノード(Text Node)を持つnameという名前の要素です。次にサンプル・コードを示します。
String value = myElement.getFirstChild().getNodeValue();
hash table key = value name = george zip = 20000が設定されているとします。
<key>value</key><name>george</name><zip>20000</zip>
ハッシュ表からキーの列挙を取得します。
enum.hasMoreElements()中にループします。
列挙内の各キーに対して、DOM文書にcreateElement()を使用して、そのキーにハッシュ表エントリのvalueの値を指定している子テキスト・ノードを持つキー名によって要素を作成します。
次の抜粋コードがあるとします。
Document doc1 = new XMLDocument();
Element element1 = doc1.creatElement("foo");
Document doc2 = new XMLDocument();
Element element2 = doc2.createElement("bar");
element1.appendChild(element2);
element1の所有者文書がdoc1で、element2の所有者文書がdoc2であるため、appendChild()ルーチンをコールすると、WRONG_DOCUMENT_ERRのDOM例外が発生します。AppendChild()は単一ツリー内でのみ動作します。この例では2つの異なるツリーを使用しています。かわりに、importNode()またはadoptNode()を使用する必要があります。
要素ノードを作成する場合、そのnodeValueはnullであるため、設定できません。次のエラーが発生します。
oracle.xml.parser.XMLDOMException: Node cannot be modified while trying to set the value of a newly created node as below: String eName="Mynode"; XMLNode aNode = new XMLNode(eName, Node.ELEMENT_NODE); aNode.setNodeValue(eValue);
次に、DTDのCDATAセクションからXMLを抽出する例を示します。
<PAYLOAD>
<![CDATA[<?xml version = '1.0' encoding = 'ASCII' standalone = 'no'?>
<ADD_PO_003>
<CNTROLAREA>
<BSR>
<VERB value="ADD">ADD</VERB>
<NOUN value="PO">PO</NOUN>
<REVISION value="003">003</REVISION>
</BSR>
</CNTROLAREA>
</ADD_PO_003>]]>
</PAYLOAD>
CDATA内にテキストとして挿入されているネストしたXML文書では異なるエンコーディングを使用できないため、埋込み文書のXML宣言を取得することはほとんど意味がありません。XML宣言を必要としない場合は、テキスト・チャンクとしてではなく実際の要素としてメッセージを<PAYLOAD>に埋め込みます。これがCDATAの機能です。
次のコードを使用します。
String s = YourDocumentObject.selectSingleNode("/OES_MESSAGE/PAYLOAD");
PAYLOADの値を選択しても、データはCDATAセクション内にあるため解析されません。
大きいテキスト・チャンクになるように要求すると、それが提供されます。ユーザーは、このテキスト・チャンクを自身で解析する必要があります(CDATA方法を使用しないメリットの1つです)。
YourParser.parse( new StringReader(s));
sは、前述の手順で取得した文字列です。
キャラクタ・セットについてのヒントを示します。
オペレーティング・システム・ファイルに格納されたXML文書を読み取る場合、FileReaderクラスを使用しないでください。かわりにXML Parser for Javaを使用して、文書の文字コードを自動で検出します。外部エンコーディング情報がないバイナリ入力ストリームの場合、パーサーは、バイト・オーダー・マークおよびXML文書のエンコーディング宣言に基づいて、文字コードを自動的に判断します。次のサンプル・コードを使用して、サポートされている任意のエンコーディングでの任意の整形式文書を正常に解析できます。
import java.io.*;
import oracle.xml.parser.v2.*;
public class I18nSafeXMLFileReadingSample
{
public static void main(String[] args) throws Exception
{
// create an instance of the xml file
File file = new File("myfile.xml");
// create a binary input stream
FileInputStream fis = new FileInputStream(file);
// buffering for efficiency
BufferedInputStream in = new BufferedInputStream(fis);
// get an instance of the parser
DOMParser parser = new DOMParser();
// parse the xml file
parser.parse(in);
}
FileWriterクラスは、実行時環境のデフォルトの文字コードに依存するため、XMLファイルを作成するときに、このクラスを使用しないでください。ドキュメントにデフォルトの文字コードで使用できない文字が含まれる場合、出力ファイルでは、解析エラーやデータの損失が発生する可能性があります。
UTF-8エンコーディングはXML文書には一般的ですが、UTF-8は、通常はJavaのデフォルトのファイル・エンコーディングではありません。デフォルトのファイル・エンコーディングを想定したJavaクラスを使用すると、問題が発生する可能性があります。次の例では、これらの問題の回避方法を示します。
mport java.io.*;
import oracle.xml.parser.v2.*;
public class I18nSafeXMLFileWritingSample
{
public static void main(String[] args) throws Exception
{
// create a test document
XMLDocument doc = new XMLDocument();
doc.setVersion("1.0");
doc.appendChild(doc.createComment("This is a test empty document."));
doc.appendChild(doc.createElement("root"));
// create a file
File file = new File("myfile.xml");
// create a binary output stream to write to the file just created
FileOutputStream fos = new FileOutputStream(file);
// create a Writer that converts Java character stream to UTF-8 stream
OutputStreamWriter osw = new OutputStreamWriter( fos,"UTF8");
// buffering for efficiency
Writer w = new BufferedWriter(osw);
// create a PrintWriter to adapt to the printing method
PrintWriter out = new PrintWriter(w);
// print the document to the file through the connected objects
doc.print(out);
}
}
NCLOB列に格納されたUTF-8エンコーディングを使用する解析XMLについて次の問題が報告されました。
データベースにロードされるXMLサンプルには、2つのUTF-8マルチバイト文字が含まれています。テキストは次のようになります。
G(0xc2,0x82)otingen, Br(0xc3,0xbc)ck_W
作成されたJavaストアド・ファンクションは、デフォルトの接続オブジェクトを使用してデータベースに接続し、SELECT問合せを実行します。また、OracleResultSetを取得し、getCLOB()メソッドをコールして、CLOBオブジェクトに対してgetAsciiStream()メソッドをコールします。次のコードを実行してXMLをDOMオブジェクトに変換します。
DOMParser parser = new DOMParser(); parser.setPreserveWhitespace(true); parser.parse(istr); // istr getAsciiStreamXMLDocument xmldoc = parser.getDocument();
コードによって、XMLに無効なUTF-8エンコーディングが含まれていることを示す例外がスローされます。文字(0xc2、0x82)は有効なUTF-8です。getAsciiStream()がコールされるときに文字に異常が発生する場合があります。
この問題を解決するには、getAsciiStream()ではなく、getUnicodeStream()およびgetBinaryStream()を使用します。
この方法が機能しない場合は、parser.parse(istr)の段階で文字がパーサーに送信される前に、文字が異常でないことを確認するために出力してみてください。
次に、アクセント付き文字を含むドキュメントの解析方法を示します。
DOMParser parser=new DOMParser();
parser.setPreserveWhitespace(true);
parser.setErrorStream(System.err);
parser.setValidationMode(false);
parser.showWarnings(true);
parser.parse ( new FileInputStream(new File("PruebaA3Ingles.xml")));
アクセント付き文字(たとえばé)をXML文書に格納して、XML Parser for JavaでそのXMLファイルを解析しようとすると、パーサーは次の例外をスローする場合があります。
'Invalid UTF-8 encoding'
アクセント付き文字は、XML文書内で次のように16進または10進形式で読み取ることができます。
é
ただし、この方法を使用しない場合は、XMLファイルの作成時に使用したキャラクタ・セットに基づいてエンコーディングを設定します。エンコーディングをISO-8859-1(Western European ASCII)に設定してみてください。使用しているツールまたはオペレーティング・システムに応じて、このエンコーディングまたはそれ以外のエンコーディングを使用します。
エンコーディングを明示的にUTF-8に設定した場合、またはエンコーディングを指定しない場合、パーサーはアクセント付き文字(127より大きいASCII値の文字)をUTF-8マルチバイト文字列の最初のバイトとして解析します。後続のバイトが有効なUTF-8文字列を構成していない場合、エラーが発生します。
このエラーは、使用するエディタがファイルをUTF-8エンコーディングで保存していないことを示します。たとえば、エディタはISO 8859-1エンコーディングを使用してファイルを保存している場合があります。エンコーディングはUnicodeの文字番号表現をディスクに書き込むために使用される特定のスキーマです。この文字列をXML文書の最上部に追加しても、エディタはファイルを表すバイトをUTF-8エンコーディングでディスクに書き出しません。
<?xml version="1.0" encoding="UTF-8"?>
メモ帳はWindowsシステムでUTF-8を使用します。
次に、一般的な質問を示します。
XML文書にバイナリ・データを直接挿入する方法はありませんが、2つの対処方法があります。
別のファイルにある外部の未解析エンティティとしてバイナリ・データを参照できます。
バイナリ・データを非エンコーディング(つまり、UUENCODEプログラムでASCIIデータに変換)して、そのデータをCDATAセクションに挿入できます。エンコーディング方法には、CDATAセクションに正当な文字のみを生成するように確認する必要があるという制限があります。
base64はコマンドライン・ユーティリティであり、MIMEでエンコードされたドキュメントで使用する形式でファイルをエンコードおよびデコードします。
ブラウザとしてIE5を使用している場合、XML文書を直接表示できます。それ以外の場合、Oracle XSLT Processorバージョン2を使用し、XSLスタイルシートを適用してHTMLドキュメントを作成します。XDK JavaBeansを使用してもXML文書を表示できます。
IE 5.0はXMLファイルを解析して、解析した出力を表示します。HTMLページをロードするようにファイルをロードしてください。
IE5でのファイルの参照やXML Parser for Javaを使用したファイルの解析に次の構文を使用します。
File: a.xml <?xml version="1.0" ?> <!DOCTYPE a [<!ENTITY b SYSTEM "b.xml">]> <a>&b;</a> File: b.xml <ok/>
a.xmlを参照および解析すると、次の文が戻されます。
<a> <ok/> </a>
XML Parser for Javaは、サポートされているバージョンのJava VMで使用できます。Oracle9i以上との唯一の違いは、パーサーをデータベースにロードし、内部JVMのOracle9i JVMを使用できる点です。その他のデータベース・バージョンまたはサーバーでは、外部JVM内でパーサーを実行し、必要に応じてJDBCを介してデータベースに接続します。
>より大きい(>)
<より小さい(<)
'アポストロフィまたは一重引用符(')
"二重引用符(")
&アンパサンド(&)
XML <COMPANYNAME>内にタグがあり、A&Bを使用する場合、パーサーでは無効な文字が原因でエラーが発生します。
&、$および#などの特殊文字は使用できません。XML文書を最初から作成する場合は、有効なNameCharsのみを使用して問題を回避できます。たとえば、<A_B>、<AB>、<A_AND_B>などを使用します。これらの文字は読み取ることができます。
データベース表などの外部データ・ソースからXMLを生成する場合、XML 1.0はこの問題に対応していません。
データ型XMLTypeは、SQL名をXML名にマップする機能によってこの問題に対応しています。SQLからXMLに名前をマップする機能によって、_XHHHH_という形式(HHHHは無効な文字のUnicode値)の無効なXML NameCharがエスケープされます。たとえば、表名V$SESSIONは、XMLの名前V_X0024_SESSIONにマップされます。
最終的に、無効な文字のエスケープも、名前を他の場所に再ロードできるようにシリアライズする方法をユーザーに提供する有効な手段です。
現在、文字列に含まれているXML文書を直接解析できる方法はありません。文字列は、解析する前にInputStreamまたはInputSourceに変換する必要があります。文字列内のバイトを使用するByteArrayInputStreamを生成する簡単な方法があります。次に例を示します。
/* xmlDoc is a String of xml */ byte aByteArr [] = xmlDoc.getBytes(); ByteArrayInputStream bais = new ByteArrayInputStream (aByteArr, 0, aByteArr.length); domParser.parse(bais);
これを実行するための例を次に示します。
XMLDocument Your Document; /* Parse and Make Mods */ : StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); YourDocument.print(pw); String YourDocInString = sw.toString();
XML Parser for Javaが&[whatever]などの実体参照を拡張せず、かわりにすべての値がnullになる場合、この問題をどのように修正できますか。
Oracleではエラーの発生なしに実体参照を処理するリグレッション・テストが行われているため、エンティティの定義または使用に単純なエラーがある可能性があります。単純なエラーには]> Alpha、&statusなどがあります。
解析した外部エンティティは、整形式のフラグメントである必要があります。CLASSPATHの次のプログラム(バージョン1のxmlparser.jarを使用)に、解析対象ドキュメントの解析と出力を示します。ここでは文字列から解析していますが、URLを指定した場合、そのメカニズムはファイルからの解析と変わりません。
import oracle.xml.parser.*;
import java.io.*;
import java.net.*;
import org.w3c.dom.*;
import org.xml.sax.*;
/*
** Simple Example of Parsing an XML File from a String
** and, if successful, printing the results.
**
** Usage: java ParseXMLFromString <hello><world/></hello>
*/
public class ParseXMLFromString {
public static void main( String[] arg ) throws IOException, SAXException {
String theStringToParse =
"<?xml version='1.0'?>"+
"<hello>"+
" <world/>"+
"</hello>";
XMLDocument theXMLDoc = parseString( theStringToParse );
// Print the document out to standard out
theXMLDoc.print(System.out);
}
public static XMLDocument parseString( String xmlString ) throws
IOException, SAXException {
XMLDocument theXMLDoc = null;
// Create an oracle.xml.parser.v2.DOMParser to parse the document.
XMLParser theParser = new XMLParser();
// Open an input stream on the string
ByteArrayInputStream theStream =
new ByteArrayInputStream( xmlString.getBytes() );
// Set the parser to work in non-Validating mode
theParser.setValidationMode(DTD_validation);
try {
// Parse the document from the InputStream
theParser.parse( theStream );
// Get the parsed XML Document from the parser
theXMLDoc = theParser.getDocument();
}
catch (SAXParseException s) {
System.out.println(xmlError(s));
throw s;
}
return theXMLDoc;
}
private static String xmlError(SAXParseException s) {
int lineNum = s.getLineNumber();
int colNum = s.getColumnNumber();
String file = s.getSystemId();
String err = s.getMessage();
return "XML parse error in file " + file +
"\n" + "at line " + lineNum + ", character " + colNum +
"\n" + err;
}
}
解析したXMLデータのリレーショナル・マッピングについて、解析したXMLデータを階層的に格納する必要があるユーザーもいます。XMLTypeはこの問題に対応しますか。
当初多くの顧客にはこの懸念があります。これは格納しているXMLの種類によって異なります。実際にリレーショナル情報(発注書など)のエンコーディングであるXMLデータグラムを格納している場合、XML文書に含まれるデータをリレーショナル表に格納することで、パフォーマンスと(SQLでの)問合せの柔軟性が大幅に向上し、特定のデータを抽出する必要がある場合は、オンデマンドでXML形式を再生成します。
訴訟手続き、書籍の章、参照マニュアルなどの複合的なコンテンツのドキュメントを格納している場合、そのドキュメントをチャンク単位で格納し、Oracle TextのXML検索機能でこれらを検索することが最善の方法です。
『Building Oracle XML Applications』(Steve Muench著)では、多くの例を掲載してこれらの格納方法や検索方法を説明しています。
XDK Parser for Javaにあいまいなコンテンツ・モードを追加する予定はありますか。
XML Parser for JavaはすべてのXML 1.0標準を実装しており、XML 1.0標準では、XML文書が明確なコンテンツ・モデルを保持する必要があります。そのため、準拠したXML 1.0パーサーがあいまいなコンテンツ・モデルを実装できる方法はありません。
マスター・ディテールの関係を使用して2つの表に基づいてXML文書を生成するとします。次の2つの表があるとします。
PARENT(ID列、PARENT_NAME列(キー列 = ID)を含む)
CHILD(PARENT_ID列、CHILD_ID列、CHILD_NAME列(キー列 = PARENT_ID + CHILD_ID)を含む)
PARENTとCHILDとの間にはマスター・ディテールの関係があります。次のような文書をどのようにして生成できるでしょうか。
<?xml version = '1.0'?>
<ROWSET>
<ROW num="1">
<parent_name>Bill</parent_name>
<child_name>Child 1 of 2</child_name>
<child_name>Child 2 of 2</child_name>
</ROW>
<ROW num="2">
<parent_name>Larry</parent_name>
<child_name>Only one child</child_name>
</ROW>
</ROWSET>
オブジェクト・ビューを使用して、マスター・ディテールの構造からXML文書を生成します。この場合、次のコードを使用します。
create type child_type is object
(child_name <data type child_name>) ;
/
create type child_type_nst
is table of child_type ;
/
create view parent_child
as
select p.parent_name
, cast
( multiset
( select c.child_name
from child c
where c.parent_id = p.id
) as child_type_nst
) child_type
from parent p
/
SQLからXMLへのマッピング・ユーティリティによって処理されるSELECT * FROM parent_childは、親子関係に対する有効なXML文書を生成します。ただし、その構造は質問で提示されたものとは異なります。次のようになります。
<?xml version = '1.0'?>
<ROWSET>
<ROW num="1">
<PARENT_NAME>Bill</PARENT_NAME>
<CHILD_TYPE>
<CHILD_TYPE_ITEM>
<CHILD_NAME>Child 1 of 2</CHILD_NAME>
</CHILD_TYPE_ITEM>
<CHILD_TYPE_ITEM>
<CHILD_NAME>Child 2 of 2</CHILD_NAME>
</CHILD_TYPE_ITEM>
</CHILD_TYPE>
</ROW>
<ROW num="2">
<PARENT_NAME>Larry</PARENT_NAME>
<CHILD_TYPE>
<CHILD_TYPE_ITEM>
<CHILD_NAME>Only one child</CHILD_NAME>
</CHILD_TYPE_ITEM>
</CHILD_TYPE>
</ROW>
</ROWSET>
Java API for XML Processing(JAXP)を使用すると、Javaアプリケーションから、SAX、DOMおよびXSLTプロセッサを使用できます。JAXPでは、特定のXMLプロセッサの実装に依存しないAPIを使用して、アプリケーションでXML文書を解析および変換できます。
JAXPには、プロセッサの実装をプラグインできるプラッガビリティ・レイヤーがあります。JAXP APIは、パーサーをプラッガブルにするためのThinレイヤーを提供する抽象クラスで構成されたAPI構造を持ちます。Oracleは、Sun社のリファレンス実装に基づいてJAXPを実装しています。
xdk/demo/java/parser/jaxpディレクトリ内のサンプル・プログラムJAXPExamples.javaおよびora.ContentHandler.javaは、JAXP APIを使用してSourceインタフェースの次のいずれかのクラスを、
DOMSourceクラス
StreamSourceクラス
SAXSourceクラス
Resultインタフェースの次のいずれかのクラスに変換する様々な方法を示します。
DOMResultクラス
StreamResultクラス
SAXResultクラス
これらの変換では、サンプル入力としてXML文書、入力としてオプション・スタイルシート、およびオプションでoraContentHandler.javaファイルに定義されたContentHandlerクラスを使用します。たとえば、identityメソッドでは、出力XML文書が入力XML文書と同じになる識別変換を実行します。別のメソッドxmlFilterChain()では、連鎖内の3つのスタイルシートを適用します。
JAXPの短所は、インタフェースに余分なコストがかかり、ネイティブなパーサーの背後に機能が存在し、処理コンポーネントでDOMを共有できない点などです。
|
関連資料: 追加の例については次の関連資料を参照してください。
|
oraxmlは、XML文書を解析するコマンドライン・インタフェースです。XML文書が整形式であるか、および妥当であるかを確認します。
oraxmlを使用するには、次の条件に該当することを確認する必要があります。
環境変数CLASSPATHが、XML V2 Parser for Javaに付属するxmlparserv2.jarファイルを指すように設定されていること。oraxmlはスキーマ検証をサポートするため、CLASSPATHにxschema.jarも含めます。
環境変数PATHが、使用しているJDKに付属するJavaインタプリタを検索できること。
表3-4に、oraxmlのコマンドライン・オプションを示します。
| オプション | 用途 |
|---|---|
|
- |
入力XMLファイルの圧縮 |
|
- |
入力圧縮ファイルの解凍 |
|
- |
DTD検証を使用した入力ファイルの検証 |
|
- |
入力ファイルのエンコーディングの出力 |
|
- |
ヘルプ・メッセージを出力します。 |
|
- |
出力ログ・ファイルへのエラーの書込み |
|
- |
入力ファイルが整形式かどうかの確認 |
|
- |
スキーマ検証を使用した入力ファイルの検証 |
|
- |
バージョン番号の出力 |
|
- |
警告の表示 |