JAXP のすべて 第 1 回

解析と検証を容易にする XML 処理ツールキット

Java API for XML Processing (JAXP) では、さまざまな API を使用して XML の検証、解析、変換を行うことができます。JAXP は使いやすく、ベンダー中立です。JAXP を紹介する 2 回シリーズの第 1 回であるこの記事では、この API の解析および検証機能を活用する方法について説明します。第 2 回では、JAXP を使用した XSL 変換について述べます。

Brett D. McLaughlin, Sr., Author and Editor, O'Reilly Media, Inc.

Photo of Brett McLaughlinBrett McLaughlin氏は、Logo (小さな三角形を覚えていますか?) の時代からコンピューターの仕事をしています。現在の専門は、JavaおよびJava関連のテクノロジーを使ったアプリケーション・インフラストラクチャーの構築です。ここ数年は、Nextel Communications and Allegiance Telecom, Inc. でこれらのインフラストラクチャーの実装に携わっています。Brett氏は、Javaサーブレットを使ってWebアプリケーション開発のための再利用可能なコンポーネント・アーキテクチャーを構築するJava ApacheプロジェクトTurbineの共同設立者の1人です。同氏はまた、オープン・ソースのEJBアプリケーション・サーバーであるEJBossプロジェクトと、オープン・ソースのXML Web公開エンジンであるCocoonにも貢献しています。



2005年 5月 07日

Java テクノロジーと XML は、過去 5 年間のプログラミングの発展の中で、おそらく最も重要なものです。結果として、Java 言語で XML を扱うための API が急増しました。最も人気の高い 2 つ、すなわち、Document Object Model (DOM) と Simple API for XML (SAX) は多大な関心を集め、JDOM とデータバインディング API がそのあとに続いています (参考文献を参照)。これらの API の 1 つか 2 つを完全に理解するのは、かなり大変です。すべての API を正しく使えたら、グールーになれます。しかし、SAX と DOM に関する深い知識はもはや必要ないと考える Java 開発者が増えています。その大部分が Sun Microsystems の JAXP ツールキットのおかげです。Java API for XML Processing (JAXP) は、初心者の Java プログラマーにとっても XML を管理しやすいものにするだけでなく、上級者にも多くのメリットを提供します。とは言うものの、上級者でも、JAXP については、自分たちが依存している API そのものについて誤解していることが少なくありません。

この記事は、読者に SAX および DOM 基本的な知識があることを前提としています。XML 解析に不慣れな場合は、まず、オンライン・ソースや私の本 (参考文献を参照) を流し読みして、SAX と DOM の勉強を少しした方がよいかもしれません。コールバックや DOM のノードに精通している必要はありませんが、少なくとも SAX と DOM が解析 API であることは理解している必要があります。それらの違いについて、ある程度理解しておくことも重要です。これらの基本的なことを理解していれば、この記事が分かりやすくなるでしょう。

JAXP:API、それとも抽象化?

厳密に言うと、JAXP は API ですが、抽象化層という方が正確です。XML を解析するための新しい手段を提供するわけでも、SAX や DOM に何かを追加するわけでも、Java と XML の取り扱いに新しい機能を与えるわけでもありません。(この点に疑問がある人こそ、この記事を読んでください。) そうではなく、JAXP は、DOM と SAX を使用して何か難しいタスクを処理するときに、その作業を容易にします。DOM および SAX API を使用しているときに遭遇する可能性のあるベンダー固有のタスクも、ベンダー中立な方法で扱えるようになります。

出世

初期バージョンの Java プラットフォームでは、JAXP はコア・プラットフォームとは別のダウンロードでした。Java 5.0 では、JAXP は Java 言語の主要素になりました。最新版の JDK (参考文献を参照) を持っている人は、すでに JAXP を持っていることになります。

SAX、DOM、またはその他の XML 解析 API がなければ、XML を解析することはできません。SAX、DOM、JDOM、dom4j と JAXP との比較に対する要求を多く見てきましたが、このような比較は不可能です。最初の 4 つの API と JAXP とでは、目的がまったく違うからです。SAX、DOM、JDOM、および dom4j はすべて、XML を解析します。JAXP はこれらのパーサーとそれらが公開するデータへの入り口を提供するものであり、XML 文書の新しい解析方法となるわけではありません。JAXP を正しく使うためには、この違いを理解することが重要です。また、この点を理解していれば、他の XML 開発者に差をつけることができるでしょう。

それでもまだ疑わしいという人は、JAXP ディストリビューションを手に入れてください (出世を参照)。Web ブラウザーを立ち上げて、JAXP API docs をロードします。API の解析部分へ移動します (javax.xml.parsers パッケージにあります)。驚くべきことに、そこには 6 つのクラスしかありません。この API が難しいわけがありません。これらのクラスはすべて、既存パーサーの上に来ます。そして、そのうちの 2 つはエラー処理に過ぎません。JAXP は、人々が思っているよりはるかに単純なのです。では、何が混乱の原因なのでしょうか。

お山の大将

JDOM と dom4j (参考文献を参照) も、JAXP と同様、他の解析 API の上部に位置します。どちらの API も SAX や DOM とは違うデータ・アクセス・モデルを提供していますが、内部では SAX を使用して (ちょっとしたトリックと修正はありますが)、ユーザーに提示するデータを入手します。

Sun の JAXP と Sun のパーサー

パーサーと API の混同の多くは、Sun が JAXP と JAXP がデフォルトで使用するパーサーとをパッケージ化した方法が原因です。JAXP の初期のバージョンでは、Sun は JAXP API (先ほど述べた 6 つのクラスと変換用のいくつかのクラスを含む) と Crimson という名前のパーサーを含めました。Crimson は com.sun.xml パッケージの一部でした。JDK に含まれる新しいバージョンの JAXP では、Sun は Apache Xerces パーサー (参考文献を参照) を再パッケージ化しました。しかし、いずれにしても、パーサーは JAXP ディストリビューションの一部であり、JAXP API の一部ではありません。

こんなふうに考えてください。JDOM は Apache Xerces パーサーとともに出荷されています。このパーサーは JDOM の一部ではありませんが、JDOM によって使用されるので、すぐに JDOM を使用できるように同梱されています。同じことが JAXP にも当てはまりますが、そのことが明確に公表されていません。JAXP にパーサーが付いているのは、すぐに使えるようにするためなのです。しかし、多くの人が、Sun のパーサーに含まれているクラスを JAXP API そのものの一部であると言っています。たとえば、ニュースグループでよくある質問は、「JAXP に付いてくる XMLDocument クラスを使うにはどうしたらよいか、何のためのものなのか」という質問です。それに対する回答は、いささか込み入っています。

(パッケージ) 名の中には何があるか

初めて Java 1.5 のソース・コードを開いてみたとき、私は自分が見たもの、と言うよりは、見なかったものに驚きました。Xerces は通常のパッケージ (org.apache.xerces) にありませんでした。Sun は Xerces クラスを com.sun.org.apache.xerces.internal に移動していました。(これは少々失礼なことだと思うのですが、だれも私に尋ねませんでした。) 何はともあれ、JDK で Xerces を探すときには、ここを探してください。

まず、com.sun.xml.tree.XMLDocument クラスは JAXP の一部ではありません。初期バージョンの JAXP にパッケージ化されていた Sun の Crimson パーサーの一部です。したがって、上記の質問は、最初から間違っています。第 2 に、JAXP の主な目的は、パーサーを扱うときにベンダー独立性を提供することです。JAXP では、Sun の XML パーサー、Apache の Xerces XML パーサー、および Oracle の XML パーサーで同じコードを使用することができます。その場合、Sun 固有のクラスを使用すると、JAXP の使用目的に反します。このテーマがいかに錯綜しているか、分かってきたのではありませんか。JAXP ディストリビューションのパーサーと API がひとまとめにされ、一部の開発者は、一方のクラスと機能をもう一方の一部と誤解しています。

さて、待ち受ける混乱のすべてを見越すことができるようになったところで、コードと概念に話を進めましょう。


SAX からの出発

SAX は XML を処理するためのイベント・ドリブンなメソドロジーです。SAX は多数のコールバックから成ります。たとえば、startElement() コールバックは、SAX パーサーがエレメントの開始タグを検出するたびに呼び出されます。文字データに対しては characters() コールバックが呼び出され、エレメントの終了タグに対しては endElement() が呼び出されます。文書処理、エラー、その他の字句構造のために、さらに多くのコールバックがあります。お分かりいただけましたか。SAX プログラマーは、これらのコールバックを定義する SAX インターフェースの 1 つを実装します。SAX には、これらのコールバックのすべてを実装して、すべてのコールバック・メソッドのデフォルトの空の実装を提供する DefaultHandler (org.xml.sax.helpers パッケージ内) というクラスもあります。(この重要性については、次のセクション「DOM の扱い」の DOM の説明の中で述べます。) SAX 開発者は、このクラスを拡張するだけで、特定のロジックの挿入を必要とするメソッドを実装できます。したがって、SAX の鍵は、これらさまざまなコールバック用のコードを提供して、適切なときにそれぞれをパーサーにトリガーさせることです。典型的な SAX ルーチンは、次のとおりです。

  1. 特定のベンダーのパーサー実装を使用して、SAXParser インスタンスを作成します。
  2. (たとえば、DefaultHandler を拡張するクラスを使用して) コールバック実装を登録します。
  3. 解析を開始して、コールバック実装が作業を終えるのを待ちます。

JAXP の SAX コンポーネントは、このすべてを実行する簡単な手段となります。JAXP を使用しない場合、SAX パーサー・インスタンスをベンダー・クラス (org.apache.xerces.parsers.SAXParser など) から直接インスタンス化するか、XMLReaderFactory という SAX ヘルパー・クラス (やはり org.xml.sax.helpers パッケージにあります) を使用しなければなりません。最初の方法の問題点は明白です。すなわち、ベンダー中立でないことです。2 番目の方法の問題点は、ファクトリーは引数として、使用するパーサー・クラスの String 名を必要とすることです (Apache クラスの場合、やはり、org.apache.xerces.parsers.SAXParser)。別のパーサー・クラスを String として渡すことによって、パーサーを変更できます。この方法では、パーサー名を変更した場合、インポート文を変更する必要はありませんが、それでもクラスを再コンパイルする必要があります。これが最上のソリューションでないことは明白です。クラスを再コンパイルしなくてもパーサーを変更できれば、その方がはるかに簡単です。

JAXP は、よりよい方法を可能にします。すなわち、パーサーを Java のシステム・プロパティーとして指定することができます。もちろん、Sun からディストリビューションをダウンロードすることによって入手できるのは、Sun バージョンの Xerces を使用する JAXP 実装です。パーサーをたとえば Oracle のパーサーに変更するには、クラスパス設定を変更し、パーサー実装を別のパーサー実装に移動する必要がありますが、コードの再コンパイルは必要ありません。そして、これが JAXP のマジックであり、抽象化なのです。

ずるい SAX 開発者

少し言い訳しておきます。コーディングをちょっと工夫すれば、SAX アプリケーションに、使用するパーサー・クラスをシステム・プロパティーやプロパティー・ファイルからピックアップさせることができます。しかし、JAXP を使用すれば、このような手間をまったくかけなくても同じことができるので、JAXP のルートを行った方がよいでしょう。

SAX パーサー・ファクトリーの概要

JAXP SAXParserFactory クラスは、パーサー実装の容易な変更を可能にする鍵です。このクラスの新しいインスタンスを作成する必要があります (もう少しあとで説明します)。新しいインスタンスが作成された後、SAX 対応パーサーを取得するための手段となるのがファクトリーです。舞台裏で JAXP 実装がベンダー依存コードの面倒を見るので、あなたのコードが汚されることはありません。このファクトリーには、他にも優れた機能がいくつかあります。

SAX パーサーのインスタンスを作成するという基本的な仕事に加えて、このファクトリーでは構成オプションを設定することもできます。これらのオプションは、ファクトリーを通じて取得されたすべてのパーサー・インスタンスに影響します。JAXP 1.3 で最もよく使われる 2 つのオプションは、setNamespaceAware(boolean awareness) による名前空間対応の設定と setValidating(boolean validating) による DTD 検証の有効化です。これらのオプションが設定されると、メソッド呼び出し後にファクトリーから取得されたすべてのインスタンスに影響を与えることを忘れないでください。

ファクトリーをセットアップした後、newSAXParser() を呼び出すと、すぐに使える JAXP SAXParser クラスのインスタンスが返されます。このクラスは、基本の SAX パーサー (SAX クラス org.xml.sax.XMLReader のインスタンス) をラップします。また、パーサー・クラスへのベンダー固有の追加を使用しないように保護します。(この記事の XmlDocument クラスの説明を覚えていますか。) このクラスによって、実際の解析動作を開始することができます。リスト 1 に、SAX ファクトリーの作成、構成、および使用方法を示します。

リスト 1. SAXParserFactory の使用
import java.io.OutputStreamWriter;
import java.io.Writer;
// JAXP
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
// SAX
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class TestSAXParsing {
    public static void main(String[] args) {
        try {
            if (args.length != 1) {
                System.err.println ("Usage: java TestSAXParsing [filename]");
                System.exit (1);
            }
            // Get SAX Parser Factory
            SAXParserFactory factory = SAXParserFactory.newInstance();
            // Turn on validation, and turn off namespaces
            factory.setValidating(true);
            factory.setNamespaceAware(false);
            SAXParser parser = factory.newSAXParser();
            parser.parse(new File(args[0]), new MyHandler());
        } catch (ParserConfigurationException e) {
            System.out.println("The underlying parser does not support " +
                               " the requested features.");
        } catch (FactoryConfigurationError e) {
            System.out.println("Error occurred obtaining SAX Parser Factory.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class MyHandler extends DefaultHandler {
    // SAX callback implementations from ContentHandler, ErrorHandler, etc.
}

リスト 1 を見ると、ファクトリーの使用に際して JAXP 固有の 2 つの問題が発生する恐れがあることが分かります。すなわち、SAX ファクトリーを取得または構成できないことと、SAX パーサーを構成できないことです。最初の問題は、FactoryConfigurationError によって表され、通常、JAXP 実装またはシステム・プロパティーで指定されたパーサーを取得できないときに発生します。2 番目の問題は ParserConfigurationException によって表され、使用されているパーサーでは要求された機能を使用できないときに発生します。どちらも簡単に対処できるので、これによって JAXP の使用が難しくなるわけではありません。実際、いくつかの機能を設定し、特定の機能が使用できない状況をグレースフルに処理するコードを書くとよいかもしれません。

SAXParser インスタンスは、ファクトリーを get したときに取得され、名前空間サポートをオフにし、検証をオンにします。その後、解析が始まります。SAX パーサーの parse() メソッドは、カスタム・ハンドラー・クラスで拡張する前述の SAX HandlerBase ヘルパー・クラスのインスタンスを取ります。このクラスの実装と完全な Java リストを確認するには、コード・ディストリビューションを参照してください (ダウンロードを参照)。解析する File も渡します。ただし、SAXParser クラスには、この単純なメソッド以外にもさまざまなメソッドが含まれています。

SAX パーサーでの作業

SAXParser クラスのインスタンスを作成した後は、解析する File を渡すだけでなく、他にもいろいろなことができます。大規模アプリケーションのコンポーネントが通信する方法により、オブジェクト・インスタンスの作成者がその使用者であると仮定するのは安全ではない場合があります。あるコンポーネントが SAXParser インスタンスを作成するときに、別のコンポーネント (おそらく別の開発者によってコード化されたコンポーネント) が同じインスタンスを使用する必要があるかもしれません。この理由から、JAXP にはパーサーの設定を調べるメソッドがあります。たとえば、isValidating() を使用して、パーサーが検証を実行するかどうかを調べることができ、isNamespaceAware() を使用して、パーサーが XML 文書の名前空間を処理できるかどうかを調べることができます。これらのメソッドによってパーサーに何ができるかを知ることができますが、SAXParser インスタンスだけを使用して、SAXParserFactory そのものを使用しなかった場合は、これらの機能を変更する手段がありません。これはパーサー・ファクトリー・レベルで行う必要があります。

文書の解析を要求する方法もいろいろあります。File および SAX DefaultHandler インスタンスを受け入れるだけでなく、SAXParser の parse() メソッドは、SAX InputSource、Java InputStream、または String 形式の URL を、すべて DefaultHandler インスタンスとともに受け入れることができます。したがって、さまざまな形式でラップされた文書を解析することができます。

最後に、基本の SAX パーサー (org.xml.sax.XMLReader のインスタンス) を入手して、それを SAXParsergetXMLReader() メソッドを通じて直接使用することができます。この基本インスタンスを取得すると、通常の SAX メソッドが使用可能です。リスト 2 に、JAXP における SAX 解析の中核的クラスである SAXParser クラスのさまざまな使用例を示します。

リスト 2. JAXP SAXParser クラスの使用
// Get a SAX Parser instance
SAXParser saxParser = saxFactory.newSAXParser();
// Find out if validation is supported
boolean isValidating = saxParser.isValidating();
// Find out if namespaces are supported
boolean isNamespaceAware = saxParser.isNamespaceAware();
// Parse, in a variety of ways
// Use a file and a SAX DefaultHandler instance
saxParser.parse(new File(args[0]), myDefaultHandlerInstance);
// Use a SAX InputSource and a SAX DefaultHandler instance
saxParser.parse(mySaxInputSource, myDefaultHandlerInstance);
// Use an InputStream and a SAX DefaultHandler instance
saxParser.parse(myInputStream, myDefaultHandlerInstance);
// Use a URI and a SAX DefaultHandler instance
saxParser.parse("http://www.newInstance.com/xml/doc.xml",
                myDefaultHandlerInstance);
// Get the underlying (wrapped) SAX parser
org.xml.sax.XMLReader parser = saxParser.getXMLReader();
// Use the underlying parser
parser.setContentHandler(myContentHandlerInstance);
parser.setErrorHandler(myErrorHandlerInstance);
parser.parse(new org.xml.sax.InputSource(args[0]));

ここまで、SAX について色々話してきましたが、驚くようなことは何もなかったはずです。JAXP によって追加された機能性は、特に SAX に関しては、かなり些細なものです。この些細な機能性が、あなたのコードの移植性を高めて、SAX 互換の XML パーサーで自由に、または商業的に、他の開発者も使えるようにします。それだけのことです。JAXP での SAX の使用には、それ以上のことは何もありません。すでに SAX を知っている人は、道のりのほぼ 98 パーセントは済んでいることになります。あとは、2 つのクラスといくつかの Java 例外を覚えるだけです。SAX を使ったことがないという人も、簡単ですから、すぐに覚えられます。


DOM の扱い

DOM という難題に取り掛かる前に休憩が必要だと思う人は、どうぞ、少し休んでください。JAXP での DOM の使用は、SAX での使用とほとんど同じです。2 つのクラス名と戻り型を変更するだけです。SAX がどのように機能し、DOM とは何かということが理解できていれば、何も問題はありません。

DOM と SAX の主な違いは、API そのものの構造にあります。SAX はイベント・ベースのコールバックのセットで構成されているのに対して、DOM はメモリー内ツリー構造です。SAX には、(開発者が手動で作成しない限り) 作用対象となるデータ構造はありません。したがって、SAX では XML 文書を修正することはできません。DOM には、この機能があります。org.w3c.dom.Document クラスは XML 文書を表し、要素、属性、およびその他の XML 構造体を表す DOM ノードで構成されています。したがって、JAXP から SAX コールバックを fire する必要はありません。JAXP の役目は、解析から DOM Document オブジェクトを返すことだけです。

DOM パーサー・ファクトリーの概要

DOM の基本とDOM と SAX の違いさえ理解していれば、それ以上知るべきことはありません。リスト 3 のコードは、リスト 1 の SAX のコードに驚くほど似ています。まず、(リスト 1 の SAXParserFactory と同じように) DocumentBuilderFactory が取得されます。次に、(SAX でと同じように) 検証と名前空間を処理するようにファクトリーが構成されます。次に、(もうお分かりのように、やはり同じように) DocumentBuilder インスタンス (SAXParser に相当) がファクトリーから取得されます。その後、解析が行われて、結果の DOM Document オブジェクトが DOM ツリーを表示するメソッドに渡されます。

リスト 3. DocumentBuilderFactory の使用
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
// JAXP
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
// DOM
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class TestDOMParsing {
    public static void main(String[] args) {
        try {
            if (args.length != 1) {
                System.err.println ("Usage: java TestDOMParsing " +
                                    "[filename]");
                System.exit (1);
            }
            // Get Document Builder Factory
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // Turn on validation, and turn off namespaces
            factory.setValidating(true);
            factory.setNamespaceAware(false);
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new File(args[0]));
            // Print the document from the DOM tree and
            //   feed it an initial indentation of nothing
            printNode(doc, "");
        } catch (ParserConfigurationException e) {
            System.out.println("The underlying parser does not " +
                               "support the requested features.");
        } catch (FactoryConfigurationError e) {
            System.out.println("Error occurred obtaining Document " +
                               "Builder Factory.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static void printNode(Node node, String indent)  {
        // print the DOM tree
    }
}

このコードでは (JAXP での SAX と同様に) 2 つの問題が発生することがあります。すなわち、FactoryConfigurationErrorParserConfigurationException です。それぞれの原因は、SAX の場合と同じです。実装クラスに問題があるか (FactoryConfigurationError)、要求された機能をパーサーがサポートしていないか (ParserConfigurationException) のいずれかです。この点での DOM と SAX の唯一の違いは、DOM では、SAXParserFactory の代わりに DocumentBuilderFactory を、SAXParser の代わりに DocumentBuilder を使用することです。それだけです。(DOM ツリーを表示するために使用されるメソッドも含めて、完全なコード・リストを見たい場合は、ダウンロードを参照してください。)

DOM パーサーでの作業

DOM ファクトリーがあれば、DocumentBuilder インスタンスを取得できます。DocumentBuilder インスタンスから使用できるメソッドは、SAXParser から使用できるメソッドとほぼ同じです。主な違いは、parse() メソッドの変化形は SAX DefaultHandler クラスのインスタンスを取らないことです。代わりに、解析された XML 文書を表す DOM Document インスタンスを返します。その他の唯一の違いは、SAX と同様の機能を提供する 2 つのメソッドが用意されていることです。

  • setErrorHandler() は、SAX ErrorHandler 実装を取り、解析中に発生する問題を処理します。
  • setEntityResolver() は、SAX EntityResolver 実装を取り、エンティティー解決を処理します。

リスト 4 に、これらのメソッドの使用例を示します。

リスト 4. JAXP DocumentBuilder クラスの使用
// Get a DocumentBuilder instance
DocumentBuilder builder = builderFactory.newDocumentBuilder();
// Find out if validation is supported
boolean isValidating = builder.isValidating();
// Find out if namespaces are supported
boolean isNamespaceAware = builder.isNamespaceAware();
// Set a SAX ErrorHandler
builder.setErrorHandler(myErrorHandlerImpl);
// Set a SAX EntityResolver
builder.setEntityResolver(myEntityResolverImpl);
// Parse, in a variety of ways
// Use a file
Document doc = builder.parse(new File(args[0]));
// Use a SAX InputSource
Document doc = builder.parse(mySaxInputSource);
// Use an InputStream
Document doc = builder.parse(myInputStream, myDefaultHandlerInstance);
// Use a URI 
Document doc = builder.parse("http://www.newInstance.com/xml/doc.xml");

DOM についてのこのセクションを読むのに少し退屈してきましたか。あなただけではありません。書いている私も少し退屈です。と言うのも、SAX について学んだことを DOM に応用するのは、実に簡単なことだからです。


検証の実行

Java 5.0 (および JAXP 1.3) で、JAXP は文書を検証する新しい方法を導入しました。単に SAX または DOM ファクトリーの setValidating() メソッドを使用するのではなく、検証が新しい javax.xml.validation パッケージ内のいくつかのクラスに分けられています。W3C XML Schema、DTD、RELAX NG スキーマ、およびその他の制約モデルも含めて、検証のニュアンスのすべてを詳しく述べるには、この記事のスペースでは足りませんが、すでに制約をある程度理解している人なら、新しい検証モデルを使用して、文書が制約に合致していることを確認するのは、かなり容易です。

冗長性は常に良いとは限らない

してはならないことのひとつは、setValidating(true)javax.xml.validation パッケージを使用することです。厄介なエラーが発生して、そのほとんどが追跡困難です。setValidating() を呼び出さずに (デフォルトで false になっています)、代わりに新しい JAXP 検証フレームワークを使用するのを習慣にすると良いでしょう。

まず、制約モデル (おそらくはディスク上のファイル) を JAXP で使用できる形式に変換します。そのファイルを Source インスタンスにロードします。(Source については第 2 回で詳しく述べます。とりあえず、ディスク上の文書を DOM Document として、またはその他ほとんどなんでも表すということだけ覚えておいてください。) 次に、SchemaFactory を作成して、SchemaFactory.newSchema(Source) を使用してスキーマをロードすると、新しい Schema オブジェクトが返されます。最後に、この Schema オブジェクトと Schema.newValidator() で新しい Validator オブジェクトを作成します。リスト 5 を見ていただくと、今の説明がよく分かると思います。

リスト 5. JAXP 検証フレームワークの使用
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File(args[0]));
// Handle validation
SchemaFactory constraintFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Source constraints = new StreamSource(new File(args[1]));
Schema schema = constraintFactory.newSchema(constraints);
Validator validator = schema.newValidator();
// Validate the DOM tree
try {
    validator.validate(new DOMSource(doc));
    System.out.println("Document validates fine.");
} catch (org.xml.sax.SAXException e) {
    System.out.println("Validation error: " + e.getMessage());
}

これは、こつさえ分かれば、かなり簡単です。このコードを自分で入力するか、または完全なリストを参照してください (ダウンロードを参照)。


パーサーの変更

JAXP ファクトリーのクラスが使用するパーサーは、簡単に変更できます。パーサーの変更は、実際にはパーサー・ファクトリーを変更することを意味します。すべての SAXParser および DocumentBuilder インスタンスは、これらのファクトリーから派生されたものだからです。どのパーサーがロードされるかはファクトリーによって決まるので、変更しなければならないのはファクトリーです。SAXParserFactory インターフェースの実装を変更するには、Java システム・プロパティー javax.xml.parsers.SAXParserFactory を設定します。このプロパティーが定義されていない場合は、デフォルトの実装 (ベンダーが指定したもの) が返されます。DocumentBuilderFactory 実装についても同様です。この場合は、javax.xml.parsers.DocumentBuilderFactory システム・プロパティーが照会されます。


まとめ

この記事を読んで、JAXP のほぼ全景が把握できたと思います。

  • SAX を利用できること
  • DOM を利用できること
  • パーサーを簡単に変更できること

JAXP の解析機能と検証機能を理解するには、ほんの少し苦労しなければなりません。JAXP を使えるようになるための最も難しい部分は、システム・プロパティーを変更すること、パーサーまたはビルダーではなくファクトリーから検証を設定すること、そしてどの部分が JAXP ではないかを明確に理解することです。JAXP は、任意のある 2 つの Java および XML API 以上に役立つプラグ可能性レイヤーとなります。みなさんのコードをベンダー中立にして、解析コードを再コンパイルしなくても別のパーサーに変更できるようにします。ですから、JAXP をダウンロードして、がんばってみましょう。第 2 回では、JAXP が XML 文書の変換にどのように役立つかを説明します。


ダウンロード

内容ファイル名サイズ
Sample code for All about JAXPx-jaxp-all-about.zip5KB

参考文献

  • XML と Java 技術を使って作業する上でのヒントを得るために、Brett McLaughlin がホストしている「XML and Java technology」フォーラムを見てください。
  • Sun のJava and XML headquartersで、JAXP について、さらに学んでください。
  • Java プログラミングが初めての人は、Java 5.0をダウンロードすれば、JDK と一緒に JAXP も入手することができます。
  • JAXP 1.3 の新しい機能を詳しく知るために、developerWorks にある 2 回シリーズの記事、「JAXP 1.3 は何が新しいのか?」を読んでください。
    • 第 1 回 (2004 年 11 月) は、JAXP 仕様の概要を簡単に説明し、javax.xml.parsers パッケージに加えられた修正の詳細や、強力なスキーマ・キャッシュや妥当性検証フレームワークについて説明しています。
    • 第 2 回 (2004 年 12 月) は、XML 仕様の名前空間で定義される概念のサポートを追加するユーティリティーに触れ、javax.xml.transform パッケージに加えられた変更を説明しています。
  • JAXP の下に隠された API について、さらに学んでください。最初は SAX の Web サイトで SAX 2 for Java を、次に W3C の Web サイトで DOM を見てください。
  • Apache Xerces パーサーの JDK 5.0 実装をダウンロードしてください。
  • SAX でベンダー非依存性を実現する」 (developerWorks, 2001 年 3 月) を読んで、SAX ベースのアプリケーションで SAX や SAX ヘルパー・クラスを使ってベンダー非依存性を実現する方法を学んでください。
  • JDOM について、さらに学んでください。JDOM は、Java 言語の中で XML 文書を容易に効率良く読み、書き、操作できるように表現するためのオープン・ソースのツールキットです。
  • JDOM で XML プログラミングを単純化する」 (developerWorks, 2001 年 5 月) を読んでください。JDOM によって、XML 文書操作がどれほど楽になるかが分かります。
  • dom4j を調べてください。dom4j は、Java プラットフォーム上で XML や XPath、XSLT を扱うための、オープン・ソースのライブラリーです。
  • Brett McLaughlin 著の Java & XML (2001 年 O'Reilly & Associates 刊) を読んでください。Java プログラマーが XML を使って Web ベースの企業アプリケーションを構築する方法を説明しています。
  • Doug Tidwell による developerWorks のチュートリアル「XML programming in Java technology, Part 1」 (2004 年 1 月) を読んで、Java 技術を使って XML 文書を操作するための基礎を学んでください。Part 2 (2004 年 7 月) は、名前空間の取り扱い、XML 文書の妥当性検証、典型的 XML 文書無しでの XML 構造構築など、より難しい話題を取り上げています。Part 3 (2004 年 7 月) は、XML データ構造の生成、こうした構造の操作、XML パーサーと非 XML データ・ソースとのインターフェースなど、さらに高度な課題を解説しています。
  • XML について、もっと基本的なことが必要であれば、developerWorks のIntro to XML tutorial (2002 年 8 月) や、その他の教育資料を試してください。これらは最も基本的な話題を網羅しています。
  • developerWorks のDeveloper Bookstoreには、広範な話題を網羅した XML 関連の書籍が取り揃えられていますので、ぜひご利用ください。

コメント

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=243901
ArticleTitle=JAXP のすべて 第 1 回
publish-date=05072005