XML catalogを使うと外部からDTDを取得せずに済むらしい。 ……ということを風の噂で何となく知る。XML catalogというのは、DTDの公開識別子やシステム識別子(URI)を、ローカルのファイルパスに置き換えてくれるもののようです。
※ 取っ掛かりがXSLTだったのでこのような文書題名になってますが、XSLTに限らずlibxml2等の汎用XMLパーサにも通用する話なので、単に「XML Catalogを使う」という題にしとけばよかった、と今では思ってます。
取り敢えず /etc/xml/catalog をこんな感じに。
<?xml version="1.0"?> <!DOCTYPE catalog PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN" "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd"> <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog"> <public publicId="-//W3C//DTD XHTML 1.1//EN" uri="xhtml11-flat.dtd"/> <public publicId="-//W3C//DTD XHTML 1.0 Strict//EN" uri="xhtml1-strict.dtd"/> <public publicId="-//W3C//DTD XHTML 1.0 Transitional//EN" uri="xhtml1-transitional.dtd"/> <public publicId="-//W3C//DTD XHTML 1.0 Frameset//EN" uri="xhtml1-frameset.dtd"/> <public publicId="-//W3C//DTD XHTML Basic 1.0//EN" uri="xhtml-basic10-f.dtd"/> </catalog>
で、同ディレクトリ内(/etc/xml)にDTDを置きました。
あとはxsltprocがcatalogを解釈してくれます。libxml2 (xmllintコマンドなど)でもこのcatalog fileが使用されます。
以下を参考に(Saxonについても載っています)。
やること:
catalogs=catalog relative-catalogs=false static-catalog=yes catalog-class-name=org.apache.xml.resolver.Resolver verbosity=1
catalogs=でcatalog fileを指定(上記は同じディレクトリ内の"catalog"ファイルを使う場合)。";"でつなげて複数指定可。
java org.apache.xalan.xslt.Process \ -ENTITYRESOLVER org.apache.xml.resolver.tools.CatalogResolver \ -URIRESOLVER org.apache.xml.resolver.tools.CatalogResolver \ -in input.xml -xsl stylesheet.xsl -out output.xml
CatalogManager.propertiesでverbosity=4にすると、DTDの解決状況が出力されます。うまく行かない時の確認などに。
WindowsのJ2RE(1.4.2_03)を使って試していたのですが、これには元々Xalan(2.4.1)が入っているらしく、ふつうにCLASSPATHにxalan.jarを設定するだけでは置き換わらない様です。このXalan(2.4.1)だと-ENTITYRESOLVERオプションをきちんと解釈してくれない……と思っていたのですが、実はただ単にresolver-1.0.jarが読み込まれていないのが原因だったようでした。
以下の記事を参考にして、lib/endorsed ディレクトリ内にresolver-1.0.jarを置くとうまくいきました。
lib/endorsed に新しいxalan.jarを置けば元からあるXalanも置き換えることができるのですが、Xalan 2.6.0を入れると文字コードの変換が上手く行かないようです(♥をshift_jisで出力する時に♥に変換せず?にしたりとか)。