Java 2 Platform, Standared Edition (J2SE) 1.4 には、JAXP 1.1 用の Crimson リファレンス実装が含まれていました。Java Platform, Standard Edition (Java SE プラットフォーム) 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
要素
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 を参照してください。
注:
互換性についても説明すべき点が 1 つあります。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 が組み込まれているという事実に依存できました。他方、ほとんどのアプリケーションでは、以降のバージョンで入手可能になった機能やバグ修正が必要でした。
しかし、内部クラスは常にクラスパスよりも優先されるため、新しいライブラリを追加しても効果はありませんでした。1.4 ではこの問題を解決するために、承認済み標準メカニズムが使用されました。しかしそのメカニズムは新しく、アプリケーション開発者だけでなくエンドユーザーにも余分の労力が必要とされました。
JAXP 1.3 以降では、実装で使用される Apache ライブラリのパッケージ名を変更することで解決します。この変更により、クラスパスで新しい Apache ライブラリを参照できるため、アプリケーション開発者はそのライブラリをこれまでと同じ方法で使用しながら、Java プラットフォームに追加されたその他の機能を利用できます。
JAXP 1.3 リファレンス実装で Apache パッケージに付けられた新しい名前は次のとおりです。
JAXP パッケージ名の変更点
JAXP 1.1 |
JAXP 1.3 以降 |
---|---|
|
|
|
|
XSLT パッケージ名の変更点
JAXP 1.1 |
JAXP 1.3 以降 |
---|---|
|
|
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
システムプロパティーを使用して増やすことができます。