レベル: 中級 Elliotte Rusty Harold (elharo@metalab.unc.edu), Adjunct Professor, Polytechnic University
2005年 5月 13日 昔のプログラマーの格言に、「どんな問題でも間接指示層を追加することで解決できる」というものがあります。これは、他の分野と同様、XMLでも的を射た格言です。スキーマ、DTD、およびスタイルシートをロードするときに起こる問題の多くは、パーサーとネットワーク・ローダーの間の間接指示としてXMLカタログを導入することによってうまく解決できます。XMLカタログによって、ドキュメントの消費者はXMLドキュメントそのもので指定された実際のURLまたはパブリック識別子を一群のURLで置き換えることができます。これにより、XML処理の速度とセキュリティの両方が改善されます。
多くのXMLドキュメントは、スタイルシート、スキーマ、DTDなどの場所を示す相対的URLを含んでいます。これらのURLが絶対URLのときでも、ファイアウォールの陰に隠れているシステムを指していることがあります。また、アクセス可能なURLの場合でも、パフォーマンス上、常に世界を半周して、同じリモート・ネットワーク・サーバーから同じDTDをリロードするのではなく、ローカル・キャッシュの使用が必要になることがあります。
IBM developerWorksサイトで使用されているXMLテンプレートを考えてみましょう。次のように始まっています。
<?xml version="1.0"?>
<?xml-stylesheet type="application/xml+xslt" href="
C:\IBM developerWorks\article-author-package\developerworks\xsl\dw-document-html-4.0.xsl"
?>
<dw-document xsi:noNamespaceSchemaLocation=
"C:\IBM developerWorks\article-author-package\developerworks\schema\dw-document-4.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
ディレクトリーC:\IBM developerWorks\article-author-package\developerworks\xslにあるスタイルシートとディレクトリーC:\IBM developerWorks\article-author-package\developerworks\schemaにあるスキーマの参照に注目してください。これらはMicrosoft® Windows®オペレーティング・システムのパス名です。私は同じファイルをMac上で書き、別の場所に格納しています。したがって、私が記事を書くときに最初にすることは、これらのURLが私のファイル・システムを指すように変更することです。
<?xml-stylesheet type=" application/xml+xslt "
href="../developerWorks/xsl/dw-document-html-4.0.xsl" ?>
<dw-document
xsi:noNamespaceSchemaLocation=
"../developerWorks/schema/dw-document-4.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
記事の初稿を書き終えたら、編集者に送ります。編集者が記事の編集作業を始めるには、Windowsを実行している編集者のマシン上のスタイルシートとスキーマの場所を指すように、これらのURLを変更しなければなりません。編集者が記事の編集を終えると、編集者の疑問に答えるために、原稿は私に送り返され、私は再びすべてのURLを変更します。私は訂正後の原稿を編集者に送り返し、編集者はdeveloperWorksの制作チームに記事を転送し、製作チームはこれらのURLを第3の場所に変更しなければなりません。このプロセスの非効率さは、少々どころではありません。
XMLカタログは、標準のURLとシステム識別子のリストを保持して、それらを特定のローカル・コピーにマップすることによって、この問題を解決します。各ユーザーは、一致するローカル・カタログをアップデートさえすれば、スキーマ、DTD、スタイルシートなどの共通ファイルのコピーを別の場所に格納することができます。その後、パーサー、スタイルシート・プロセッサー、スキーマ・バリデーター、またはその他のツールがドキュメントを読み取るときには、ドキュメントそのものの中のURLではなく、カタログ内のURLから補助ファイルをロードします。
カタログには、著者と編集者の作業を容易にするだけでなく、他にもいくつかのメリットがあります。たとえば、www.w3.orgなどのリモートWebサイトのXHTMLドキュメントを読むことを考えてみましょう。このようなドキュメントは、通常、次のようなDTDを含んでいます。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
パーサーがDTDを読み取る場合、リモートWebサーバーからXMLドキュメントをロードしなければならないだけでなく、http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtdにある、おそらくさらに大きなリモートDTDも読み取らなければなりません。ネットワーク速度と遅延が問題になります。カタログを使用すると、同じDTDのローカル・コピーをロードするようにパーサーに指定することができ、はるかに速くロードできます。
URLリダイレクションによって、ある種の攻撃も防ぐことができます。たとえば、XMLドキュメントをシステムに取り込んで、外部DTDサブセットのシステム識別子を変更すれば、検証するDTDが変更されることになります。カタログを使用すると、ドキュメントの作成者ではなくドキュメントを解析する人が、使用するDTDを選ぶことができます。ただし、このリダイレクションは完璧な保護ではありません。内部DTDサブセットをベクトルとして使用する攻撃もあり、カタログは内部DTDサブセットに影響しないからです。
単純なキャッシングに加えて、カタログを使用すると、DTDまたはスキーマを別のDTDまたはスキーマに置き換えることができます。たとえば、エンティティーを定義するだけで、エレメントや属性を宣言しない変形のXHTML DTDを使用したい場合があります。このDTDは、完全なDTDがローカル・システムからロードされた場合でも、完全なDTDよりも解析と適用がはるかに高速です。また、特定の属性のATTLIST宣言を変更することによって、デフォルト属性値を変更することができます。カタログを選ぶ理由が何であれ、効果は同じです。すなわち、カタログを使用すると、ドキュメントの作成者ではなくドキュメントを読み取る人が、使用するDTD(またはスキーマやスタイルシート)を選ぶことができます。
カタログの構文
リスト1に、簡単なカタログを示します。このカタログそのものがXMLドキュメントです。ルート要素は、urn:oasis:names:tc:entity:xmlns:xml:catalog名前空間内のcatalogです。このカタログには3つのpublic要素が含まれ、それぞれ特定のパブリック識別子を特定のURLにマップします。たとえば、パブリックID-//W3C//DTD XHTML 1.0 Strict//ENはURL file:///opt/xml/xhtml/DTD/xhtml1-strict.dtdにマップされます。
リスト1. 単純なXHTMLカタログ
<?xml version='1.0'?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<public publicId="-//W3C//DTD XHTML 1.0 Transitional//EN"
uri="file:///opt/xml/xhtml/DTD/xhtml1-transitional.dtd "/>
<public publicId="-//W3C//DTD XHTML 1.0 Strict//EN"
uri="file:///opt/xml/xhtml/DTD/xhtml1-strict.dtd "/>
<public publicId="-//W3C//DTD XHTML 1.0 Frameset//EN"
uri="file:///opt/xml/xhtml/DTD/xhtml1-frameset.dtd "/>
</catalog>
|
このカタログが設定されたパーサーで、次のようなドキュメントを読み取る場合を考えてみましょう。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
DTDをダウンロードするためにhttp://www.w3.orgに2度目のネットワーク接続を行う必要はありません。代わりに、パス/opt/xml/xhtml/DTD/xhtml1-strict.dtdにあるローカル・ファイル・システムからロードします。
もちろん、カタログはhttp URLだけでなく相対URLにリダイレクトすることもできます。たとえば、リモート・サーバーではなくローカル・ネットワーク上のサーバーに格納されているDTDのコピーを参照したり、ソース・ドキュメントと同じディレクトリーにあるDTDのコピーを参照したりすることができます。
カタログを使用すると、public要素とpublicId属性の代わりに、system要素とsystemId属性を使用してシステム識別子を再マップすることもできます。この再マップは、パブリック識別子ではなくシステム識別子だけで参照されるDTDおよびエンティティー定義に便利です。リスト2は、この再マップを使用して、パブリック識別子ではなくW3CサイトURLに基づいたXHTML DTDのローカル・コピーをロードする方法を示しています。(リスト2は例に過ぎません。パブリック識別子が使用できるときには、パブリック識別子の方がはるかに信頼できるキーです。)
リスト2:システム識別子に基づくXHTMLカタログ
<?xml version='1.0'?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<system systemId="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
uri="file:///opt/xml/xhtml/DTD/xhtml1-transitional.dtd "/>
<system systemId="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
uri="file:///opt/xml/xhtml/DTD/xhtml1-strict.dtd "/>
<system systemId="http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
uri="file:///opt/xml/xhtml/DTD/xhtml1-frameset.dtd "/>
</catalog>
|
通常はシステム識別子によってもパブリック識別子によっても参照されないスタイルシートなどについては、uri要素を使用できます。この要素のname属性は、マッピング元のURIを指定します。uri属性は、マッピング先のURIを指定します。リスト3は、http://schemas.xmlsoap.org/wsdl/soap/からhttp://localhost:8888/schemas/soap.xsdへ、このリダイレクト要求を使用する方法を示しています。
リスト3:ローカルWebサーバーからのSOAPスキーマのロード
<?xml version='1.0'?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<uri name="http://schemas.xmlsoap.org/wsdl/soap/"
uri="http://localhost:8888/schemas/soap.xsd "/>
</catalog>
|
カタログは、URLツリー全体を書き直すのに非常に便利です。rewriteSystemおよびrewriteURI要素は、特定のサーバーまたはディレクトリーのすべてのファイルの代替場所を指定します。リスト4に、http://www.example.com/data/のファイルに対するすべての要求をhttp://www.example.net/mirror/にリダイレクトする方法を示します。
リスト4:URIを書き換えるコード
<?xml version='1.0'?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<rewriteURI uriStartString=" http://www.example.com/data/"
rewritePrefix=" http://www.example.net/mirror/ "/>
</catalog>
|
たとえば、このカタログを使用しているパーサーがファイルhttp://www.example.com/data/tic/article.xsl を要求した場合、実際にはファイルhttp://www.example.net/mirror/tic/article.xsl を取得します。書き換えはプレフィックスに基づいて制限されます。したがって、たとえば、rewriteURIを使用して.htmlファイルに対するすべての要求を.xhtmlファイルに対する要求にリダイレクトすることはできません。
 |
システム識別子対URI
uriとsystemの両方の要素とrewriteURIとrewriteSystemの両方の要素があるのは少し変です。実際には、すべてのシステム識別子はURIであり、URIと別のシステム識別子の両方を持つ構造体はありません。system要素とrewriteSystem要素は、XML 1.0仕様でシステム識別子として定義されているもの、すなわち、基本的に文書型宣言と外部エンティティー定義で使用されるURIについてだけ使用されます。その他のものについては、uriおよびrewriteURI要素が使用されます。 |
|
各要素の例を個別のカタログ・ファイルで示しましたが、このすべてを1つのカタログに入れることもできます。同じ識別子について複数のマッピングがある場合は、最初に検出されたものが優先されます。同じリソースが複数の識別子を持つ場合(たとえば、パブリック識別子とシステム識別子の両方を持つDTD)、動作はシステムに依存します。ただし、カタログ要素にprefer="system"またはprefer="public"属性を指定して、どちらを優先すべきかを指定することができます。
カタログには、さらに高度なリダイレクトに使用できる高度な機能がほかにもあります。次のようなものがあります。
- 相対URL解決のための
xml:base属性
- 特定の種類のパブリックおよびシステム識別子について追加のカタログをロードする
delegatePublicおよびdelegateSystem要素
- 複数のカタログをチェーン化する
nextCatalog要素
- 複数のエントリーを結合する
group要素
- ドキュメントのプロローグの
<?oasis-xml-catalog?>処理命令によって指定されるドキュメント固有のカタログ
ただし、一般的な使用例では、public、system、rewriteSystem、uri、およびrewriteURIだけで、ほとんどカバーできます。
カタログ・ソフトウェア
すでに多くのXMLソフトウェアがXMLカタログ・サポートを組み込んでいます。たとえば、Gnome Projectのlibxml Cライブラリーは、/etc/xml/catalogにあるカタログを自動的にロードします。$XML_CATALOG_FILES環境変数で新しい場所を指定することによって、カタログを探す場所を変更することができます。カタログをロードしたくない場合は、$XML_CATALOG_FILESを空の文字列に設定します。
プログラムがJava™言語で書かれていて、SAXパーサーを使用してXMLを読み取る場合は、EntityResolverとしてNorm Walshのカタログ・フィルターをインストールできます(現在はApache XML Commons Projectの一部)。同じクラスが、xsl:importおよびxsl:include要素、また、document()関数で、XSLTスタイルシート内で見つかったURLを解決するためのTrAXURIResolverとしても機能します。たとえば、このコードの断片は、カタログを使用するようにSAXパーサーを設定します。
EntityResolver resolver = new org.apache.xml.resolver.tools.CatalogResolver();
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setEntityResolver(resolver);
|
CatalogResolverオブジェクトは、xml.catalog.files Javaシステム・プロパティーをチェックして、カタログを見つけます。このプロパティーには、カタログ・ファイルのURLがセミコロンで区切られたリストとして含まれています。
Apache Forrestドキュメンテーション・フレームワークとApache Cocoon Webパブリッシング・フレームワークは、どちらもこの同じXML CommonsCatalogResolverクラスとカタログ・ファイルを使用して、提供するドキュメント内のリンクをソートします。
他の主要なツール、ライブラリー、環境のほとんどに、同様のオプションが存在します。カタログ・ファイルをロードする方法については、マニュアルを参照してください。カタログ・サポートを有効にする具体的な方法はツールやライブラリーによってさまざまですが、カタログの形式はすべて共通です。
まとめ
世界中が1つのファイル・レイアウト構造に合意することはありえません。システム間でXMLドキュメントを移動すると、スタイルシート、スキーマ、DTD、およびその他のメタコンテンツへのリンクが切れてしまいます。XMLカタログは、ドキュメントが予期している正確な場所にファイルがないときでも、リンクに影響を与えない便利な間接指示層となります。XMLドキュメントとその補助ファイルを、互いの単純なミラー・コピーではない複数の異種システム間で同期させておく必要があるときには、カタログは貴重です。また、カタログは、リモート・ネットワーク・リソースの代わりにローカルでキャッシュされたコピーをロードすることによって、XML処理を迅速にします。最後に、カタログは、DTDがスワップされないことを保証し、XMLパーサーがファイアウォールの外にトンネリングするのを防止することによって、セキュリティを高めます。カタログ・サポートは、おそらく、皆さんがお使いのツールの多くにすでに組み込まれているので、カタログは多くの困難な問題に対する容易な解決策となります。
参考文献
著者について
記事の評価
|