J2SE 1.4 プラットフォームには、JAXP 1.1 の「Crimson」リファレンス実装が含まれていました。J2SE 5 プラットフォームには、Apache 「Xerces」 ライブラリに基づく JAXP 1.3 のリファレンス実装が含まれています。
これらの実装はまったく異なるコードベースが基になっており、かつ JAXP 標準は 1.1 から 1.3 へと発展したため、J2SE 1.4 と J2SE 5 では、その実装が 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
を参照してください。
注:
互換性のある点も説明します。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 ライブラリをダウンロードしてインストールし、classpath に指定する必要があります。
この変更点は、標準 JAXP API を使用するように制限されているアプリケーションには影響ありません。ただし、以前の JAXP バージョンで定義された XML プロセッサの実装固有の機能にアクセスするアプリケーションでは、JAXP 1.3 で変更されたパッケージ名を使用するように変更する必要があります。
変更により、従来のアプリケーションには次の影響があります。
J2SE 1.4 では、JAXP が Java プラットフォームに組み込まれたということには利点も欠点もありました。一方、アプリケーションは、JAXP が組み込まれているという事実に依存することができました。他方、ほとんどのアプリケーションでは、以降のバージョンで入手可能になった機能やバグ修正が 必要でした。
しかし、内部クラスは常に classpath よりも優先されるため、新しいライブラリを追加しても効果はありませんでした。1.4 ではこの問題を解決するために、承認済み標準機構が使用されました。しかしその機構は新しく、アプリケーション開発者だけでなくエンドユーザにも余分の労 力が必要とされました。
JAXP 1.3 参照名では、実装で使用される Apache ライブラリのパッケージ名を変更することで解決します。この変更により、classpath で新しい Apache ライブラリを参照できるため、アプリケーション開発者はそのライブラリをこれまでと同じ方法で使用しながら、Java プラットフォームに追加されたその他の機能を利用できます。
JAXP 1.3 リファレンス実装で Apache パッケージに付けられた新しい名前は次のとおりです。
JAXP 1.1
JAXP 1.3
JAXP org.apache.crimson
-/-
com.sun.org.apache.xerces.internalorg.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
システムプロパティを使用して増やすことができます。