XSLT関数をWindows上のPHP4.3.4で実行する際の注意

ページ情報
制作日
2003-12-23
最終更新日
2003-12-23
参照用URI
http://www.arielworks.net/articles/2003/1223a
分野

パスの指定の仕方

XSLT関数を使う場合、Windows上ではファイルパス指定方法がわかりにくいので自分で実験して最も汎用性が高い物を書いておきます。

@ITのPHPでのXSL変換の記事によると

まずはパスの区切り文字である「\」は「/」に変更しなければなりません。そして、ドライブ文字列である「C:」の部分を取り除きます。結果、変数$strDirには「/Program Files/Apache Group/Apache2/htdocs/atmarkit」のような文字列が格納されます。現行のXSLT関数はこのパス形式でのみ絶対パスを認識することができます。

XML文書をXSLTスタイルシートに動的に紐付ける(PHP編)(@IT:XMLテクニック集)』より引用。

とのことですが、これは少なくともWindowsXP上のPHP4.3.4では間違っていると言えます。

XSLT関係でパスを指定する状況はまず、xslt_process()関数のXML、XSL、出力先ファイルのパス指定、xslt_set_base()関数による基準URI(パス)指定、XMLファイル内での他のファイルの参照、例えばDOCTYPE宣言などです。

これらxslt_process()関数が処理するファイル内の全てのパスは基本的に同じ仕組みで扱われます。いかにその法則を示します。

  1. パスがスラッシュから始まる場合、Apacheがインストールされているドライブのルートディレクトリからのパスとする。
  2. 1以外の場合で先頭がfile://から始まる場合は、そのパスを最終的なパスとする。(例:file://D:/foo/bar.xml => D:/foo/bar.xml)
  3. 1以外の場合で先頭がhttp://から始まる場合、指定したパスは開かれない。
  4. 1、2、3以外の場合、つまり「foo/bar.xml」のようなパスの場合、アパッチがインストールされているディレクトリからのパスとする。
  5. ディレクトリの区切りはスラッシュとバックスラッシュ(円マーク)どちらも使用できる

この法則に従うと、最も使いやすいのがfile://を先頭に付ける方法です。Linux上のPHP4.3.4ではfile://が付いていても問題なく動作するので、例えば

xslt_process( $handle,
    "file://" . $_SERVER['DOCUMENT_ROOT'] . $xml,
    "file://" . $_SERVER['DOCUMENT_ROOT'] . $xsl,
    "file://" . $_SERVER['DOCUMENT_ROOT'] . $output
);

のように書いて$xml$xsl$outputにそれぞれドキュメントルートからのパス「/foo/bar.xml」等を書いておけば環境に依存することなくXSLT処理を行えます。

このサイト内のPHPはHTMLとの親和性を高めるため、ドキュメントルートからのパスを基本に変数を設定してfopen()xslt_process()など、絶対パスが必要なときにだけ$_SERVER['DOCUMENT_ROOT']を追加しています。絶対パスを変数にしておくとHTMLでリンク(<a href="/foo/bar.xml">hoge</a>)などに使うドキュメントルートからのパスを逆算する作業が面倒になるのでこの方法をお勧めします。

問題点

xslt_set_base()はXSLT関数が扱うパスほぼ全ての基準パスになります。先ほどの4の場合に相対パスの基準がApacheがインストールされているディレクトリになるのを避けたい場合はxslt_set_base()で設定しておけば解決します。注意点としては以下のものがあります。

xslt_set_base( $handle, "file://D:/foo/bar/hoge" );
xslt_process( $handle, "smpl.xml", "smpl.xsl", "out.xml" );

このように記述した場合、xslt_process()が開こうとするXMLファイルはD://foo/bar/hoge/smpl.xmlではなくてD://foo/bar/smpl.xmlになります。

これは、xslt_set_base()はD:/foo/bar/hogeがディレクトリかどうかは解釈せず、D:/foo/bar/hoge(.xmlが付いていると考えると分かりやすい)から相対パスsmpl.xmlにリンクしているのと同じ事になるからです。ディレクトリだと明言するためには最後にスラッシュを付けてfile://D:/foo/bar/hoge/としなくてはいけません。

最後にXMLファイル内でDOCTYPE宣言している際の注意です。システム識別子のURIも上記の法則で解釈されます。

これによって、クライアントサイトとサーバサイド、どちらでもXSL変換を可能にするのが困難になります。http://www.arielworks.net/hoge.dtdを参照する際、サイト内のXMLで<!DOCTYPE bar SYSTEM "/hoge.dtd">と絶対パスで参照しているとクライアントサイドのブラウザではルートがhttp://www.arielworks.net/になるのに対し、サーバサイドのXSLT関数ではスラッシュから始まっているためどうやってもApacheのインストールされているディレクトリのルートになってしまいます。

解決策としては

$data_xml = preg_replace(
    "/<!DOCTYPE (.+?) SYSTEM \"(\/.*)\">/",
    "<!DOCTYPE $1 SYSTEM \"file://" . $_SERVER['DOCUMENT_ROOT'] . "$2\">",
    $data_xml );

のようにPHPで予め置換しておくしか有りません。

連絡先、リンク、転載や複製などについては「サイト案内」をご覧ください。Powered by HIMMEL