XSLT関数を使う場合、Windows上ではファイルパス指定方法がわかりにくいので自分で実験して最も汎用性が高い物を書いておきます。
まずはパスの区切り文字である「\」は「/」に変更しなければなりません。そして、ドライブ文字列である「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()
関数が処理するファイル内の全てのパスは基本的に同じ仕組みで扱われます。いかにその法則を示します。
この法則に従うと、最も使いやすいのが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で予め置換しておくしか有りません。