ヒント: classpathからリソースをロードする

Java classpathでのSAX EntityResolverの使用

SAX APIには、XML文書内のリソースを見付けるためのEntityResolver インターフェースが備わっています。このヒントでは、ローカルJava classpathを使用してこのインターフェースで実体(entity)を解決する方法について説明します。

Brett McLaughlin (brett@newInstance.com), Author and Editor, O'Reilly Media Inc.

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



2002年 8月 01日

SAX APIを構築する基本的なブロックの1つは、実体解決のプロセスです。このプロセスはorg.xml.sax.EntityResolver インターフェースによって処理されます。残念ながら、多くの場合EntityResolver インターフェースは、すべてとは言わないまでもほとんどの熟練したSAXデベロッパーによって無視されています。これは、必ずしもそうでなければならないわけではありません。このインターフェースを使用すれば、アプリケーションであらゆる種類のパフォーマンス向上が可能になるからです。優れたEntityResolver インプリメンテーションを使用すれば、劇的に構文解析の速度を上げ、リソース管理を単純化することができます。

単純な実体解決

最も単純に言うと、EntityResolver は、SAXパーサー・インプリメンテーションに、XML文書で指定されたリソースを検索する方法を伝えます。リスト1 は、実体参照を含むXML文書フラグメントです。

リスト1. 実体参照を含むXML
<footer>
  <smallText>&copyright;</smallText>
</footer>

リスト1 の単純な文書フラグメントは、実体参照 (名前:copyright) を示しています。SAX構文解析プロセスは、この実体参照を処理する際に、実体を別の内容に解決しなければなりません。構文解析プロセスは、最初に文書のDTDまたはXMLスキーマで、リスト2 のような定義を検索します。

リスト2. 実体参照の定義
<!ENTITY copyright PUBLIC "-//IBM//TEXT DeveloperWorks Copyright//EN"
    "copyright.xml"
>

この参照から、パーサーは実体参照のパブリックID (-//IBM//TEXT DeveloperWorks Copyright//EN) とシステムID (copyright.xml) を判別します。次に、構文解析プロセスは、現在のXMLReader インプリメンテーションにEntityResolver インプリメンテーションが登録されているかどうかを調べます。登録されていれば、DTDやスキーマから抽出されたパブリックIDとシステムIDを使用して、resolveEntity() メソッドを呼び出します。リスト3 は、EntityResolver インプリメンテーションを最も単純な形で示しています。

リスト3. 最も単純な形のEntityResolver
import java.io.IOException;
import org.xml.sax.SAXException;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
public class SimpleEntityResolver implements EntityResolver {
    public InputSource resolveEntity(String publicId, String systemId)
        throws SAXException, IOException {
        // Returning null means use normal resolution
        return null;
    }
}

このインプリメンテーションは、実行するたびに単純にnull を戻し、通常の実体解決を行うことをパーサーに指示します。パブリックIDと (その後で) システムIDは、参照のIDによって指定されているように、インターネットまたはローカル・ファイル・システムで検索されます。この例では、パーサーはパブリックIDをインターネットで解決し、それが失敗した場合にcopyright.xml という名前のローカル・ファイルを検索します。次いで、このプロセスの内容が文書に挿入されます。

インターネットでのリソースの検索は時間がかかり、文書が構文解析されるたびにアプリケーションの速度が低下します。これに対処するため、必要なすべての参照とリソースをローカル・ファイル・システムにダウンロードするのが一般的です。それらのローカル・ファイルがオンライン・リソースの代わりに使用されることを保証するため、デベロッパーは しばしばXMLの制約セットを変更し、実体参照定義のシステムIDでファイルやダウンロード済みリソースのローカル・コピーを指定したりします。残念ながら、これはよくない考えです。参照が、特定の位置の特定のファイル・システムにある特定のファイルに束縛されてしまうからです。

より良い解決策は、文書の制約を独立させ、必要なすべてのリソースを、アプリケーションで使用するXML文書およびJavaクラスとともにjarファイルにパッケージすることです。つまり、使用するライブラリ (XMLパーサーなど)、アプリケーション・ファイル (Javaクラス)、XML文書および制約、そしてXMLで参照されるリソース (copyright.xml ファイルなど) をまとめることになります。jarファイルを使用すれば、必要なすべてのリソースがjarファイルに含まれているので、デプロイメントは非常に単純になります。次いで、このアーカイブをJava classpathに追加できます。


実体リゾルバーを登録する

最後のステップでは、現在のclasspathで実体参照を検索する実体リゾルバーを登録します。リスト4 はそのようなリゾルバーを示しています。

リスト4. classpathによる実体の解決
import java.io.InputStream;
import java.io.IOException;
import org.xml.sax.SAXException;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
public class ClassPathEntityResolver implements EntityResolver {
    public InputSource resolveEntity(String publicId, String systemId)
        throws SAXException, IOException {
        InputSource inputSource = null;
      try {
            InputStream inputStream =    EntityResolver.class.getResourceAsStream(
                    systemId);
            inputSource = new InputSource(inputStream);
        } catch (Exception e) {
            // No action; just let the null InputSource pass through
        }
        // If nothing found, null is returned, for normal processing
        return inputSource;
    }
}

XML参照のシステムIDがcopyright.xml であれば、単純にリソースをjarファイルの最上位レベルに置き、その名前をcopyright.xml にしておきます。次いで、ClassPathEntityResolver のインスタンスをXMLReader に登録し、構文解析と解決を開始します。

参考文献

コメント

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
ArticleID=242157
ArticleTitle=ヒント: classpathからリソースをロードする
publish-date=08012002