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

Java classpathでのSAX EntityResolverの使用

Comments

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 に登録し、構文解析と解決を開始します。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML
ArticleID=242157
ArticleTitle=ヒント: classpathからリソースをロードする
publish-date=08012002