J2SE 1.4 プラットフォームには、JAXP 1.1 の「Crimson」リファレンス実装が含まれていました。J2SE 6 プラットフォームには、Apache 「Xerces」 ライブラリに基づく JAXP 1.4 のリファレンス実装が含まれています。
これらの実装はまったく異なるコードベースが基になっており、かつ JAXP 標準は 1.1 から 1.4 へと発展したため、どちらも JAXP 標準に準拠していますが、これらの実装間にはわずかな差異があります。これら 2 つの要因が組み合わさるために、このガイドで説明する互換性の問題が発生しています。
リリースノートを参照してください。
J2SE 1.4 のリファレンス実装では DOM Level 2 API をサポートしていますが、J2SE 6 の実装では DOM Level 3 ファミリの API をサポートしています。このセクションでは、この変更に伴う、JAXP 1.1 リファレンス実装を使用するプログラムへの影響を説明します。
詳細は、DOM Level 3 の付録 Changes にある変更点の完全な一覧を参照してください。
DOM Level 3 では、次のインタフェースにメソッドが追加定義されました。
Attr
Document
DOMImplementation
Element
Entity
Node
Text
追加されたメソッドにより影響を受けるのは、インタフェースを直接実装しているアプリケーションだけで、それもそのようなアプリケーションを再コンパイルしたときだけです。アプリケーションでこれらのインタフェースの実装クラスを取得するためにファクトリメソッドを使用している場合は、問題ありません。
これらの変更の影響を受けるアプリケーションは、XML データを DOM に読み込んで変更し、元のデータ形式を保持しながら書き出すようなアプリケーションです。
JAXP 1.1 では、余分な空白は入力時に自動的に削除されました。このとき、たとえばエンティティーノードや CDATA ノードを保持するために、単一プロパティー (ignoringLexicalInfo) が false に設定されていました。これらのノードを含めることで、DOM は処理がいくらか複雑になっていました。 しかしこれらのノードが含まれているために空白出力 (インデントや新規行) が追加され、可読性が高く、書式化された、入力内容に非常に近い XML データを出力できました。
JAXP 1.4 では、処理に利用できる字句 (書式) 情報の程度を判別するためにアプリケーションが使用する API が 4 つあり、それぞれ以下の DocumentBuilderFactory メソッドを使用します。
setCoalescing()
CDATA ノードを Text ノードに変換し、隣接する
Text ノードがあれば、そのノードに追加する
setExpandEntityReferences()
エンティティー参照ノードを展開する
setIgnoringComments()
コメントを無視する
setIgnoringElementContentWhitespace()
空白が要素の内容に重要でない場合は、
その空白を無視する
これらのプロパティーのデフォルト値はどれも 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);
EntityResolver API の resolveEntity() メソッドで、IOException と SAXException をスローするようになった。これまでは SAXException だけがスローされていた。
DefaultHandler をこのような方法で使用するアプリケーションはごく一部だけである。 また、DefaultHandler 実装クラスが追加の例外を宣言するように変更されたため、ほとんどのアプリケーションはこの影響を受けない
アプリケーションに影響があるのは、resolveEntity() メソッドをオーバーライドして、かつ super.resolveEntity() を呼び出す場合だけである。この場合、アプリケーションは、super.resolveEntity() がスローする IOException を処理するようにメソッドを変更するまで、J2SE 5 でコンパイルされない
新機能は次のとおり
http://xml.org/sax/features/external-general-entities
外部の一般的なエンティティーを含めることができる
http://xml.org/sax/features/external-parameter-entities
外部のパラメータエンティティーと、外部の DTD サブセットを含めることができる。
また、新しいプロパティーは次のとおり
http://xml.org/sax/properties/xml-string
現在のイベントに関連する文字列を取得する
Xerces の機能およびプロパティーの完全な一覧は、http://xerces.apache.org/xerces2-j/features.html および http://xerces.apache.org/xerces2-j/properties.html を参照してください。
注:
互換性のある点も説明します。J2SE 1.4 (JAXP 1.1) では、名前空間の認識は、デフォルトでオフになりました。下位互換性のため、この方針は J2SE 6 (JAXP 1.4) でも変わりません。ただし、www.saxproject.org から入手できる公式の SAX 実装では、名前空間の認識がデフォルトで「オン」になっています。JAXP の観点からは厳密には互換性の問題となりませんが、思いがけない結果を招くことがあります。
標準 JAXP API を使用し、XSL トランスフォーマを作成したり XSL トランスフォーマにアクセスしたりするコードは、変更する必要がありません。出力は同じですが、たいていの場合は生成が高速になります。 これは、 Xalan トランスフォーマではなく、XSLTC のコンパイルトランスフォーマがデフォルトで使用されるためです。
注:
XSL スタイルシートの開発やテストなど、小さいデータセットで 1 回実行する場合は、Xalan と XSLTC のパフォーマンス上の大きな差はありません。しかし、大きなデータセットで XSLTC を使用する場合には、パフォーマンス上の大きな利点があります。
JAXP 1.4 では、XPath 表現を評価するための標準 XPath API を提供します。この API を使用することをお勧めします。Xalan 解釈は、リファレンス参照に含まれていません。アプリケーションで単独の XPath 表現 (XSLT スタイルシートの一部でないもの) を評価するために Xalan XPath API を明示的に使用している場合は、Xalan 用の Apache ライブラリをダウンロードしてインストールする必要があります。
この変更点は、標準 JAXP API を使用するように制限されているアプリケーションには影響ありません。ただし、1.3 以前の JAXP バージョンで定義された XML プロセッサの実装固有の機能にアクセスするアプリケーションは、変更する必要があります。
変更により、従来のアプリケーションには次の影響があります。
内部実装にアクセスするために使用されていたプロパティー値を変更する必要がある
Xalan 実装クラスから内部 API を使用するアプリケーションでは、そのような API にアクセスするための import 文を変更する必要がある
Crimson 実装から内部 API を使用していたアプリケーションは、記録する必要がある。このとき可能であれば、新しい JAXP API または、必要に応じて Xerces API を使用する。
J2SE 1.4 では、JAXP が Java プラットフォームに組み込まれたということには利点も欠点もありました。一方、アプリケーションは、JAXP が組み込まれているという事実に依存することができました。他方、ほとんどのアプリケーションでは、以降のバージョンで入手可能になった機能やバグ修正が 必要でした。
しかし、内部クラスは常に classpath よりも優先されるため、新しいライブラリを追加しても効果はありませんでした。1.4 ではこの問題を解決するために、承認済み標準機構が使用されました。しかしその機構は新しく、アプリケーション開発者だけでなくエンドユーザーにも余分の労 力が必要とされました。
JAXP 1.3 以降では、実装で使用される Apache ライブラリのパッケージ名を変更することで解決します。この変更により、classpath で新しい Apache ライブラリを参照できるため、アプリケーション開発者はそのライブラリをこれまでと同じ方法で使用しながら、Java プラットフォームに追加されたその他の機能を利用できます。
JAXP 1.3 リファレンス実装で Apache パッケージに付けられた新しい名前は次のとおりです。
|
JAXP 1.1 |
Since JAXP 1.3 |
JAXP |
org.apache.crimson |
-/- |
|
org.apache.xml |
com.sun.org.apache.xml.internal |
XSLT |
org.apache.xalan |
com.sun.org.apache.xalan.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
システムプロパティーを使用して増やすことができます。