JAXP 1.3は何が新しいのか? 第1回

技術の概要および、構文解析APIの変更と新しい妥当性検証APIの考察

XMLは成熟した技術でありながら、それを取り巻く状況には驚くほど活発な動きがあります。Java™ API for XML Processing (JAXP) 1.3 が最近最終決定され、今やXMLに関連した最新のオープン・スタンダードの多くがJ2SEプラットフォームに参入するための通り道となっています。JAXP 1.3 APIを説明する2回シリーズの記事の今回は、著者のNeil GrahamとElena LitaniがJAXP仕様の簡単な概要とjavax.xml.parsersパッケージに加えられた変更の詳細を説明し、また強力なスキーマのキャッシュと妥当性検証フレームワークについて解説します。

Neil Graham (neilg@ca.ibm.com), Manager, XML Parser Development, IBM

Neil Grahamは、IBMのXMLパーサ開発のマネージャです。ApacheのXerces-Java と Xerces-C++ XMLパーサに関するコミッターであり、主に XML Schema と XML 1.1、それに文法キャッシュの実装に従事しています。JAXP 1.3を開発したエキスパート・グループのIBM代表の一人でもあります。



Elena Litani (elitani@ca.ibm.com), Staff Software Developer, IBM

Elena Litaniは、IBMで働くソフトウェア開発者です。Eclipse.org において、SDO(Service Data Objects)に関するリファレンス実装を提供している、EMF(Eclipse Modeling Framework)プロジェクトの主要な貢献者の一人です。以前は、Apache Xerces2プロジェクトの主要な貢献者として、Xerces2 XML Schema や DOM Level 3 の実装、またパーサのパフォーマンスの解析や改善に取組んできました。W3C DOM Working GroupではIBM代表を務めたこともあり、DOM Level 3仕様の開発にも参加していました。



2004年 11月 09日

元来Java API for XMLParsingと命名されたJAXP 1.0は、単にアプリケーションがDOM Level 1あるいはSAX 1.0のパーサを作成できるようにするための、ベンダーから中立の手段を提供していました。2001年にJAXP 1.1が登場すると「P」は、Parsing(構文解析)ではなくProcessing(処理)を表すようになり、またAPIの適用範囲も広くなって、アプリケーションがXSLTプロセッサとやりとりするための標準的な手段を提供するようになりました。JAXP 1.1は、Java 2 Standard Edition (J2SE) 1.4とJava 2 Enterprise Edition (J2EE) 1.3の、両方の一部となっています。JAXP 1.2は、2002年にJAXP 1.1のマイナーな改訂版として登場し、JAXP準拠のパーサでW3C XML Schemaの妥当性検証を呼び出すための標準的な手段を追加しました。

J2SE 5とJ2EE 4の一部となるはずのJAXP 1.3は、このAPIにとって3年ぶり以上にもなる、メジャーなリリースです。2回シリーズのこの記事では、JAXPの新しいバージョンで追加された新しい機能のそれぞれの領域を探って行くことにします。

JAXP 1.3の概要

JAXPの仕様は、下記の仕様を保証し、またこれらに基づいて作成されています(参考文献参照)。

  • XML 1.0 (3rd Edition) と XML 1.1、W3C勧告
  • Namespaces in XML 1.0 (正誤表を含む) と Namespaces 1.1、W3C勧告
  • XML Schema (正誤表を含む)、W3C勧告
  • XSL Transformations (XSLT) Version 1.0、W3C勧告
  • XML Path Language (XPath) Version 1.0 (正誤表を含む)、W3C勧告
  • XML Inclusions (XInclude) Version 1.0、この記事の執筆時点ではW3C勧告案
  • Simple API for XML (SAX) 2.0.2 (sax2r3) と SAX Extensions 1.1

すべてのJAXP 1.3準拠の実装は、上記の仕様をサポートする必要があります。

JAXP APIは、幾つかのJavaパッケージを含んでおり、そのそれぞれがJAXPの機能の一部を提供しています。

  • javax.xml: これはルート・パッケージです。この中には、便利な定数を定義する一つのクラス(XMLConstants)のみが含まれています。
  • javax.xml.parsers: このパッケージはJAXP 1.0の時から存在しています。これには、SAXあるいはDOMを使ってXML文書を構文解析し妥当性検証するための、ベンダーに中立なAPIを定義しています。
  • javax.xml.transform: このパッケージはJAXP 1.1の時から存在しています。これには、XSL Transformations(XSLT)のAPIを定義しています。
  • javax.xml.namespace: これはJAXP 1.3で追加された新しいパッケージです。これには、名前空間の操作を可能にするQNameクラス とNamespaceContextインターフェースを定義しています。これらのクラスは元々、Java API for XML-Based RPC (JAX-RPC)仕様で定義されたものです(参考文献参照)。
  • javax.xml.datatype: これはJAXP 1.3で追加された新しいパッケージです。これには、W3C XML Schemaのデータ型 と Javaの型の間でのマッピングを完全にするために、新しいJavaの型を定義しています。
  • javax.xml.validation: これはJAXP 1.3で追加された新しいパッケージです。ここで定義されたAPIを使用することで、アプリケーションがスキーマ(例えばW3C XML Schema)をキャッシュしてXML文書の妥当性検証に使えるようになります。
  • javax.xml.xpath: これはJAXP 1.3で追加された新しいパッケージです。これには、XPath式を文書に対して適用するための(データ・モデルや実装に依存しない)APIを定義しています。

JAXPには、SAX APIを含むorg.xml.saxパッケージと、DOM Level 3 APIを含むorg.w3c.domパッケージも含まれています(参考文献参照)。


JAXP 1.3とXMLの構文解析

特定バージョンのJAXPに依存しているアプリケーションの可搬性が最大限に保たれるように、JAXP仕様のバージョンは最初から、特定バージョンのDOMとSAX、そしてその基礎となるXMLとXML名前空間仕様とに結びつけられてきました。こうした仕様の中で、JAXPのこれまでの大幅な改訂(JAXP 1.1)以来この3年間、一定していたものは一つもありませんでした。ですからJAXP 1.3は、こうしたそれらの仕様の最新版に合わせ、こうした仕様がJ2SEやJ2EEに取り込まれるようにしています。

XML標準の進化

W3Cは2004年の初めに、XML 1.0 3rd Edition と XML 1.1、そして XML名前空間 1.1 を完成させました。JAXP 1.3は、JAXP 1.3準拠のパーサに対して、この3つの全てを実装するように要求しています。XML 1.0 3rd Edition で言及しているのは、最も厳格なXMLアプリケーションでのみ問題となるような曖昧な点の明確化がほとんどです。一方XML 1.1は、XMLの名前として使用できる文字を劇的に拡張したことによって、XMLの世界に(好ましい意味で)非常に大きな衝撃を与えるはずです。これはXMLに対してUnicode標準との上位互換性を考慮し、行末に関するXMLとUnicodeでの定義を調整し、また、0(ゼロ)を除く全てのASCII文字(全ての制御文字を含む)に対する参照を含めた条項を記載することによって明確化されています。名前空間 1.1では、文書断片の内部で名前空間接頭辞を宣言しないでおくことができ、そして当然ながらこれはXML 1.1を基準としています。こうした仕様についてさらに詳しくは、developerWorksの記事「XML 1.1と名前空間1.1を明らかにする」を見てください。

W3Cではもう一つ、現在は勧告案である XML Inclusions (XInclude) 1.0 を扱っています。XIncludeは、XML文書が他のXML文書やテキスト型リソースの、一部または全部を含むことができるような手段を提供しています。これはXMLの実体とは異なり、完全にDTD(Document Type Definitions)の枠組みの外で行われ、従ってXML Schemaの妥当性検証には好都合なものです。またこれは、名前空間を想定して設計されています。多くの文書間で共有されるコンテンツを持つXMLリソースの作者にとっては、XIncludeが非常に貴重なものとなるでしょう。JAXP 1.3では、JAXP 1.3に準拠する全ての実装に対して、XIncludeがW3C勧告になるまで、この仕様に追従するように規定しています。

JAXP では、XMLを構文解析するAPI自体に関して、SAX 2.0.2 と SAXのExtensions 1.1、そしてDOM Level 3 Core と DOM Level 3 Load and Save を保証しています。DOM Level 3仕様は、それ自体で新しい機能の重要な部分を表しており、従ってこの記事の範囲を超えています。IBMのdeveloperWorksには、既にDOM Level 3 Coreに関する素晴らしい記事が何本かありますので(参考文献参照)、興味のある方はそちらをご覧ください。

バージョン番号の違いが小さいことから分かる通りSAX 2.0.2は、JAXP 1.1が保証していたSAX 2.0と大幅に違っているわけではありません。SAX 2.0.1は、署名の互換性に関する幾つかの変更を含んでいました(そのためにJAXP 1.2では保証されませんでした)。例えば・・・、SAXで定義された例外クラスに対するデフォルト・コンストラクタの追加や、EntityResolver#resolveEntityコールバックのスロー句に対するIOExceptionの追加などですが、それらを除けば、事実上SAX 2.0とまったく同じものでした。SAX 2.0.2では、新たな定義として次のようなものを追加しています。

  • アプリケーションがSAXパーサに対して、XML 1.1をサポートしているか否かを照会できる機能
  • XMLの名前と名前空間をJVMの定数プール中に保持するようにパーサに指示する機能。intern文字列に対しては、文字列が等価か否かの判定に、String.equals()の代わりに「==」を使うことができます。
  • XML 1.1正規化チェックを有効にする機能。JAXP 1.3では、JAXP 1.3準拠のパーサに対して、この機能をサポートするように要求していないことに注意してください。

Extensions 1.1は、SAXの元々の拡張から大幅に改善されています。追加されたものの一例を以下に記述します。

  • EntityResolver2 インターフェースは、DTDの外部サブセットに対するコールバックを提供することによって、EntityResolver を拡張し、baseURI と実体の名前をresolveEntityメソッドのパラメータ・リストに追加します。
  • Attributes2 は、各属性がDTDの中で宣言されるかどうか、または属性値がDTDによってデフォルトになっているか否かに関する情報を提供することによって、Attributes を拡張します。
  • Locator2 は、getXMLVersion()getEncoding() を追加することによって、Locatorを拡張します。これによって、現在処理されている実体のXML宣言に関する疑似属性に完全にアクセスできるようになります。

javax.xml.parsersへの機能追加

JAXP 1.3が直接定義する構文解析関連のインターフェースに対する変更は、驚くほど重大なもの・・・ではありません。恐らく最も一般的に役立つ変更は、reset()メソッドに関するものでしょう(DocumentBuilderSAXParser の両方に追加されており、これらのオブジェクトがそのデフォルト状態に戻れるようにしています)。パーサ・オブジェクトに対するJAXPのファクトリ機構は、非常に高価なものなので、アプリケーションではしばしばSAXParserDocumentBuilder のプール(pool)を実装しようとします。こうすることで構文解析タスクが必要になった時に、これらのオブジェクトが使用でき、構文解析タスクが完了した後にも必ずしも破棄する必要がありません。オブジェクトを既知の状態にリセットする機能によって、オブジェクトを必要としているコードがそのオブジェクトをどのように使うかに関して、プールは何も知らなくて済みます。またパーサを利用しているコードに対して、(今コードがアクセスを許されている)そのパーサが、それ以前にどのように使われていたかを知ることも必要ではありません。これによって、こうしたプール機構がずっと効率的になり、また実装も容易になるはずです。パーサ・プールの実装方法については、「XMLアプリケーションのパフォーマンスを改善する 第2回」を読んでください。

パーサとスキーマは、SAXParserFactoryDocumentBuilderFactory に追加されたsetSchema() メソッドを通して結びつけることができます(下記のjavax.xml.validationパッケージに関する説明を見てください)。これによって、特定のスキーマ(javax.xml.validation.Schemas)のために最適化されたパーサを構成することが許されることになります。これによって、文書の妥当性検証の根拠となる文法に関して何ら組み込みの知識を持たない標準的なパーサ・オブジェクトと比較して、かなりのパフォーマンスを改善することができます。またアプリケーションは、ファクトリに含まれるget/setXIncludeAwareメソッドを使ってパーサ・ファクトリを設定し、XIncludeを認識するパーサを生成することもできます。パーサおよびファクトリに対して、XIncludeを認識するかどうかをisXIncludeAware()メソッドを通して照会することができます。またパーサやファクトリに現在関連付けられているSchema を(もし存在すれば)getSchema()メソッドで取得することができます。


妥当性検証とスキーマをキャッシュするJAXP API

多くのアプリケーションでは、W3C XML Schema勧告に従って定義されたようなスキーマに対してXML文書の妥当性検証をしようとしています。妥当性検証プロセッサが、文書の妥当性を検証するには、スキーマ文書を構文解析し、このスキーマに対する内部的なメモリ内表現を構築し、次にこのメモリ内のスキーマを使ってXML文書の妥当性を検証します。ですから、もし妥当性検証プロセッサが、それぞれのXML文書を妥当性検証する前にスキーマのメモリ内表現を構文解析して構築する必要がある場合には、妥当性検証は大きなパフォーマンス・コストを要求するものになります。ただし通常は、アプリケーションが持っているスキーマのセットは限られています。ですからアプリケーションは、プロセッサに対して、与えられたスキーマに対するメモリ内表現を一度構築し、それを使って文書の妥当性検証をすべきなのです。

これまでは、それぞれの実装がスキーマのキャッシュに関して独自の機構を用意する必要がありました。例えばApache Xerces-Jパーサは、独自の文法キャッシュAPIを定義しています(参考文献参照)。今では、JAXP 1.3が標準のAPI(javax.xml.validationパッケージ)を定義しており、これを使うことでアプリケーションがスキーマを再利用できるようになり、従って全体的なパフォーマンスが改善されることになります。

妥当性検証APIを詳しく見て行きましょう。スキーマのメモリ内表現を取得するためにはまず、このファクトリが具体的にどのスキーマ言語をサポートするのかを規定する、スキーマ・ファクトリ(javax.xml.validation.SchemaFactory)のインスタンスを取得する必要があります。JAXPに準拠した実装では、W3C XML Schemaをサポートする必要があります。RELAX NGなどのような、他の言語のサポートはオプションです。XMLパーサを設定するのと同じように、機能やプロパティを使ってファクトリを設定します。そして最終的に、与えられた(単一の、あるいは複数の)スキーマのメモリ内表現を構築するように、ファクトリに対して要求するのです。スキーマのメモリ内表現は、Schemaクラスとして定義されます。そしてこれは不変なので、スレッド・セーフです。このAPIは、スキーマの構造やプロパティの取得を許可するような手段を何も提供していません。

Schemaクラスには、幾つかの使い方があります。

  • 妥当性検証に対して、(先に述べた通り)与えられたスキーマのメモリ内表現を使うように最適化されたパーサを構築することができます。
  • Schemaクラスを使うことで、このSchemaを使う異なったXML入力ソース(DOMやSAXなど)の妥当性検証ができるバリデータを生成することができます。

まず、与えられたスキーマのメモリ内表現を再利用することで、構文解析のパフォーマンスをどのように改善するかを説明しましょう。説明を単純にするために、リスト1 のサンプル・コードでは、注文書を表すXML文書(po.xml)と注文書のスキーマ(po.xsd)を使います。この文書とスキーマのどちらも、W3C XML Schema Primer勧告(参考文献参照)で定義されています。

まずスキーマ・ファクトリを構成し、それを使って注文書スキーマのメモリ内表現を構築します。次にDOMファクトリのインスタンスを取得し、このファクトリに注文書スキーマ(schema)を設定します。そして、DOMファクトリを使ってDOMパーサを生成します。この新しいパーサでは、注文書スキーマに対するXML文書の妥当性検証のみが行えます。

リスト1. XML文書の構文解析と妥当性検証でSchemaを再利用する
// create a SchemaFactory that conforms to W3C XML Schema
  SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
  // set your error handler to catch errors during schema construction
  sf.setErrorHandler(myErrorHandler);
  // parse the purchase order schema
  Schema schema = sf.newSchema("po.xsd");
  // get a DOM factory
  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  // configure the factory
  dbf.setNamespaceAware(true);
  // set schema on the factory
  dbf.setSchema(schema);
  // create a new parser that validates documents against
  // the schema specified (po.xsd)
  DocumentBuilder db = dbf.newDocumentBuilder();
  // attach an error handler to detect document validation errors
  db.setErrorHandler(myErrorHandler);
 // parse and validate against po.xsd an XML document
  Document purchaseOrderDoc = db.parse("po.xml");

ここで、バリデータの使い方を見てください。特定のスキーマから、2種類のバリデータを生成することができます。

  • Validator は、DOMあるいはSAXソースの妥当性検証を行うことができ、オプションとして、DOMイベント、SAXイベントをそれぞれ生成します。
  • ValidatorHandler は、SAXイベントのストリームに対して妥当性を検証します。このバリデータは、SAXのContentHandlerとして機能します。もしバリデータ・ハンドラに独自のorg.xml.sax.ContentHandlerを設定すると、バリデータ・ハンドラは入ってくるSAXイベントの妥当性を検証し、イベントをContentHandlerに転送するフィルタとして機能します。このバリデータでは、TypeInfoProviderインターフェースを使って、要素や属性に対する型情報を取得することもできます(ValidatorHandler.getTypeInfoProvider()メソッドを見てください)。

これらのバリデータは、どれもスレッド・セーフではありません。バリデータは、元のデータに何らかの追加情報を補うことによって、検証結果のデータを変更するかも知れません。例えば妥当性検証の結果として、DOMツリーにデフォルト属性が現れたり、新しいSAXイベントが発生したりする可能性があります。様々な機能やプロパティを設定してバリデータを構成することができ、またバリデータが外部実体を解決するのを助けるために実体リゾルバ(org.w3c.dom.ls.LSResourceResolver)を登録したり、あるいはエラー・ハンドラ(org.xml.sax.ErrorHandler)を付加したりすることもできます。もしエラー・ハンドラが何も付加されていないならば、デフォルト実装はどのような妥当性検証エラーに対してもSAXParseExceptionをスローすることに注意してください。

リスト2 は、Validatorインターフェースを使ってDOM文書の妥当性を検証する方法を示しています。この例では、アプリケーションが po.xsd と ipo.xsd という2種類のスキーマに対してDOM文書の妥当性を検証することを想定しています。アプリケーションは、別のアプリケーションからDOM文書を受け取っているかも知れず、あるいは既存のDOM文書に何らかの修正を加えているかも知れません。その上で、DOM文書が po.xsd と ipo.xsd に従って、相変わらず妥当であることを確認しようとしています。

リスト2. DOM文書の妥当性検証にValidatorインターフェースを使う
// create JAXP transformation sources to specify
  // schema sources you want to use
  StreamSource po = new StreamSource("po.xsd");
  StreamSource ipo = new StreamSource("ipo.xsd");
  // build in-memory representation for po.xsd and ipo.xsd
  Schema schemas = sf.newSchema(new Source[]{po, ipo});
  // create a validator that will be able to validate
  // against po.xsd and ipo.xsd
  Validator validator = schemas.newValidator();
  // configure this validator
  validator.setErrorHandler(myErrorHandler);
  // specify a DOM tree that you want to validate
  DOMSource docSource = new DOMSource(purchaseOrderDoc);
  // validate the source
  validator.validate(docSource, null);

まとめ

この記事では、基本的なXML標準の改訂に関する解説や構文解析APIに加えられた修正を含めて、JAXP APIの一般的な概要を説明しました。さらに、新しいjavax.xml.validationパッケージの詳細と、それによってアプリケーションにおけるXMLの構文解析パフォーマンスがどのように改善されるかも説明しました。次回の第2回では、JAXP 1.3での新しいデータ型のサポートやJAXP 1.3が名前空間サポートに関して提供する汎用的なユーティリティ、またjavax.xml.transformパッケージに加えられた変更、そしてデータ・モデルにもベンダーにも中立なXPath 1.0 APIを持つ、新しいjavax.xml.xpathパッケージなどについて紹介する予定です。

参考文献

  • JAXP(Java API for XML Processing) についてさらに学んでください。
  • W3C Technical Reports ページを見るとW3C仕様の全てが分かります。
  • XML文書po.xml と注文書スキーマpo.xsd は、どちらもW3C XML Schema Primer勧告 で定義されています。
  • JAX-RPC(Java API for XML-Based RPC) について読んでみてください。
  • SAX(Simple API for XML)DOM(Document Object Model) について、その仕様を読んでみてください。
  • Elena Litani と Arnaud Le Hors による DOM Level 3 Core に関する2回シリーズの記事を読んでみてください。
    • Part 1 では、ノードの操作と比較、文字列とユーザ・データの処理について解説しています(developerWorks, 2003年8月)。
    • Part 2 では、ブートストラップ、XML Infoset、型情報へのアクセス、Xercesの取り扱いに踏み込んでいます(developerWorks, 2003年8月)。
  • XML 1.1 と Namespaces 1.1 がどんなものか、どのような変化をもたらすのか、またどのように他の仕様やユーザに影響するのかを、Arnaud Le Horsによる「XML 1.1と名前空間1.1を明らかにする」で学んでください(developerWorks, 2004年5月)。
  • developerWorksにある「XMLアプリケーションのパフォーマンスを改善する」シリーズの全記事・・・第1回(2004年7月)、第2回(2004年7月)、第3回(英語、2004年9月)・・・を読んでXMLアプリケーションを強化する方法を学んでください。
  • Xerces2 Java パーサと、その文法キャッシュAPIについて学んでください。
  • RELAX NG をよく見てください。これはOASIS(Organization for the Advancement of Structured Information Standards) が維持管理しており、またOASISとISO(International Organization for Standardization) の両方の標準になっています。
  • 世の中にあふれるXMLの標準に混乱している人は、Uche OgbujiがdeveloperWorksに書いている、XML標準に関する記事を読んで整理すると良いでしょう。
    • 第1回: 核となる標準
    • 第2回: XML処理の標準
    • 第3回: 最も重要なボキャブラリ
    • 第4回 (US): 最も重要なXML標準の相互参照表
  • developerWorksのXMLゾーンおよびJava technologyゾーンには、関連した資料が他にも豊富に取り揃えられています。
  • XMLおよび関連技術においてIBM認証開発者になる方法についてはこちら を参照してください。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Java technology
ArticleID=239893
ArticleTitle=JAXP 1.3は何が新しいのか? 第1回
publish-date=11092004