J2SE 1.4 プラットフォームには、JAXP 1.1 の「Crimson」リファレンス実装が含まれていました。J2SE 5 プラットフォームには、Apache「Xerces」ライブラリに基づく JAXP 1.3 のリファレンス実装が含まれています。
これらの実装はまったく異なるコードベースが基になっており、かつ JAXP 標準は 1.1 から 1.3 へと発展したため、どちらも JAXP 標準に準拠していますが、これらの実装間にはわずかな差異があります。これら 2 つの要因が組み合わさるために、このガイドで説明する互換性の問題が発生しています。
1.4 用に作成された XML アプリケーションには、いくらかの互換性の問題があるとはいえ、J2SE 5 プラットフォームの JAXP 1.3 にはそれを上回る利点があります。
以上が改善点です。しかし、いくつかの互換性の問題が残っています。本ドキュメントの残りの部分では、これらの問題について説明します。
J2SE 1.4 のリファレンス実装では DOM Level 2 API をサポートしていますが、J2SE 5 の実装では DOM Level 3 ファミリの API をサポートしています。このセクションでは、この変更に伴う、JAXP 1.1 リファレンス実装を使用するプログラムへの影響を説明します。
詳細は、DOM Level 3 の付録「Changes」にある変更点の完全な一覧を参照してください。
DOM Level 3 では、次のインタフェースにメソッドが追加定義されました。
追加されたメソッドにより影響を受けるのは、インタフェースを直接実装しているアプリケーションだけで、それもそのようなアプリケーションを再コンパイルしたときだけです。アプリケーションでこれらのインタフェースの実装クラスを取得するためにファクトリメソッドを使用している場合は、問題ありません。
これらの変更の影響を受けるアプリケーションは、XML データを DOM に読み込んで変更し、元のデータ形式を保持しながら書き出すようなアプリケーションです。
JAXP 1.1 では、余分な空白は入力時に自動的に削除されました。このとき、たとえばエンティティーノードや CDATA ノードを保持するために、単一プロパティー (ignoringLexicalInfo) が false に設定されていました。これらのノードを含めることで、DOM は処理がいくらか複雑になっていました。しかしこれらのノードが含まれているために空白出力 (インデントや改行) が追加され、可読性が高く、書式化された、入力内容に非常に近い XML データを出力できました。
JAXP 1.3 では、処理に利用できる字句 (書式) 情報の程度を判別するためにアプリケーションが使用する API が 4 つあり、それぞれ以下の DocumentBuilderFactory メソッドを使用します。
これらのプロパティーのデフォルト値はどれも false で、受け取ったドキュメントを元の形式に再構築するために必要な字句情報がすべて保持されます。これらのプロパティーをすべて true に設定すると、もっとも単純な DOM が構築できるため、アプリケーションでは字句構文の詳細を考慮することなく、データのセマンティックコンテンツに集中できます。
注:
新しいノードを追加するときは、可読性を高めるために必要となるインデントや改行の書式は自動的に付加されないため、アプリケーションで付加する必要があります。
SAX 2.0.0 と SAX 2.0.2 で行われた変更で、互換性に影響を及ぼす可能性のあるものは以下のとおりです。
DeclHandler.externalEntityDecl
は、DTDHandler.unparsedEntityDecl
との一貫性を保つため、現在では絶対システム識別子を返すパーサーを必要とする。 このため、非互換性が生じる可能性がある。SAX 2.0.1 では、アプリケーションは ErrorHandler、EntityResolver、ContentHandler、または DTDHandler を null に設定できる。このようにすると SAX 2.0 では NullPointerException (NPE) が発生していたが、この制約が緩くなった。
そのため、JAXP 1.3 では、次のコードも有効
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader reader = sp.getXMLReader();
reader.setErrorHandler(null);
reader.setContentHandler(null);
reader.setEntityResolver(null);
reader.setDTDHandler(null);
問題が生じるような方法で DefaultHandler を使用するアプリケーションはごく一部だけであり、また、DefaultHandler 実装クラスが追加の例外を宣言するように変更されたため、ほとんどのアプリケーションはこの影響を受けない。
アプリケーションに影響があるのは、resolveEntity() メソッドをオーバーライドして、かつ super.resolveEntity() を呼び出す場合だけである。この場合、アプリケーションは、super.resolveEntity() がスローする IOException を処理するようにメソッドを変更するまで、J2SE 5 でコンパイルされない。
また、新しいプロパティーは次のとおり
Xerces の機能およびプロパティーの完全な一覧は、http://xml.apache.org/xerces2-j/features.html および http://xml.apache.org/xerces2-j/properties.html を参照してください。
注:
互換性についても説明すべき点が 1 つあります。J2SE 1.4 (JAXP 1.1) では、名前空間の認識は、デフォルトでオフになっていました。下位互換性のため、この方針は J2SE 5 (JAXP 1.3) でも変わりません。ただし、www.saxproject.org から入手できる公式の SAX 実装では、名前空間の認識がデフォルトでオンになっています。JAXP の観点からは厳密には互換性の問題となりませんが、思いがけない結果を招くことがあります。
標準 JAXP API を使用し、XSL トランスフォーマを作成したり XSL トランスフォーマにアクセスしたりするコードは、変更する必要がありません。出力は同じですが、ほとんどの場合は生成が高速になります。これは、Xalan トランスフォーマを解釈する代わりに、XSLTC のコンパイルトランスフォーマがデフォルトで使用されるためです。
注:
XSL スタイルシートの開発やテストなど、小さいデータセットで 1 回実行する場合は、Xalan と XSLTC のパフォーマンス上の大きな差はありません。しかし、大きなデータセットで XSLTC を使用する場合には、パフォーマンス上の大きな利点があります。
JAXP 1.3 は、XPath 表現を評価するための標準 XPath API を提供します。 この API を使用することをお勧めします。 Xalan インタプリタ型トランスフォーマは、リファレンス参照に含まれていません。アプリケーションがスタンドアロン XPath 表現 (XSLT スタイルシートの一部でないもの) を評価するために Xalan XPath API を明示的に使用している場合は、Xalan 用の Apache ライブラリをダウンロードしてインストールし、クラスパスに指定する必要があります。
この変更点は、標準 JAXP API を使用するように制限されているアプリケーションには影響ありません。ただし、以前の JAXP バージョンで定義された XML プロセッサの実装固有の機能にアクセスするアプリケーションでは、JAXP 1.3 で変更されたパッケージ名を使用するように変更する必要があります。
変更により、従来のアプリケーションには次の影響があります。
J2SE 1.4 では、JAXP が Java プラットフォームに組み込まれたということには利点も欠点もありました。一方、アプリケーションは、JAXP が組み込まれているという事実に依存できました。他方、ほとんどのアプリケーションでは、以降のバージョンで入手可能になった機能やバグ修正が必要でした。
しかし、内部クラスは常にクラスパスよりも優先されるため、新しいライブラリを追加しても効果はありませんでした。1.4 ではこの問題を解決するために、承認済み標準メカニズムが使用されました。しかしそのメカニズムは新しく、アプリケーション開発者だけでなくエンドユーザーにも余分の労力が必要とされました。
JAXP 1.3 参照名では、実装で使用される Apache ライブラリのパッケージ名を変更することで解決します。この変更により、クラスパスで新しい Apache ライブラリを参照できるため、アプリケーション開発者はそのライブラリをこれまでと同じ方法で使用しながら、Java プラットフォームに追加されたその他の機能を利用できます。
JAXP 1.3 リファレンス実装で Apache パッケージに付けられた新しい名前は次のとおりです。
JAXP 1.1 |
JAXP 1.3 |
|
JAXP | org.apache.crimson |
-/- com.sun.org.apache.xerces.internal |
org.apache.xml | com.sun.org.apache.xml.internal | |
XSLT | org.apache.xalan org.apache.xpath org.apache.xalan.xsltc |
com.sun.org.apache.xalan.internal com.sun.org.apache.xpath.internal com.sun.org.apache.xalan.internal.xsltc |
アプリケーションが標準 API に存在しない機能にアクセスするには、コマンド行で -D を使ってシステムプロパティーを指定しますが、このとき JRE の lib/jaxp.properties ファイル内で指定するか、またはアプリケーション内にハードコーディングして指定することが一般的です。
JAXP 1.3 には、多くの新機能があります。そのようなアプリケーションをアップグレードするときは、同じジョブを行う javax.xml.* パッケージで標準 API を検索することをお勧めします。これは、将来のアプリケーション変更を避けるのに最善の方法です。どうしても必要な場合 (機能上の制約や、新 API を検証する時間がないなど)、パッケージ名をこれまでの形式から次の形式に変換してプロパティーの値を変更できます。
org.apache.somePackage --> com.sun.org.apache.SomePackage.internal
同様に、内部実装クラスすべてで、新しいパッケージ名を使用します。アプリケーションで実装クラスを使用している場合 (推奨されない方法)、そのようなパッケージ名も変更する必要があります。
XML では、再帰的なエンティティー定義は認められませんが、入れ子にされたエンティティー定義は認められます。しかし、外部ソースからの XML データを許可するサーバーがサービス妨害攻撃を受ける可能性があります。たとえば、次のように非常に深く入れ子にされたエンティティー定義が含まれる SOAP ドキュメントは、エンティティーを展開するのに CPU 時間の 100% と大量のメモリーを消費してしまいます。
<?xml version="1.0" encoding ="UTF-8"?> <!DOCTYPE foobar[
<!ENTITY x100 "foobar"> <!ENTITY x99 "&x100;&x100;"> <!ENTITY x98 "&x99;&x99;"> ... <!ENTITY x2 "&x3;&x3;"> <!ENTITY x1 "&x2;&x2;"> ]> <SOAP-ENV:Envelope xmlns:SOAP-ENV=...> <SOAP-ENV:Body> <ns1:aaa xmlns:ns1="urn:aaa" SOAP-ENV:encodingStyle="..."> <foobar xsi:type="xsd:string">&x1;</foobar> </ns1:aaa> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
外部 XML データを受け入れないシステムではこの問題を考慮する必要はありませんが、受け入れるシステムではこの問題を防ぐために、次のような予防手段のどれかを利用できます。
entityExpansionLimit
システムプロパティーを使用して増やすことができます。