Makefileをbuild.xmlに書換える
Makefile
このサイトはXMLとXSLTでXHTMLに変換しています.XSLTプロセッサはXTで,変換の要否はmakeで判定しています.例えばトップページの場合,Makefileはこのようになります.makeはcygwinのmakeを使っています.
XSL=./xsl XSLT=${XSL}/top.xsl XSLTP=java -cp "${PROGRAMFILES}/xt/xt.jar;${PROGRAMFILES}/xt/lib/xp.jar;${XSL}" com.jclark.xsl.sax.Driver index.html:index.xml ${XSLT} ${XSLTP} index.xml ${XSLT} index_unformatted.html "${XSL}/format.pl" index_unformatted.html>index.html rm index_unformatted.html
format.pl
は作成したXHTMLファイルの体裁を整えるためのperlスクリプトです.このような内容になっています.
#!/usr/bin/perl -p s/^\t//g; s/\sxmlns=""//g; s/^\t+(<\!DOCTYPE.*)/$1/; s/^\t+(<html.*)/$1/; s!(<meta[^>]*/>|<link[^>]*/>|<title>|<script[^>]*>|<\!--)!\n\t$1!g; s!(</?head>|</?body>|<div[^>]*>|<h1>|<p>|<dl>|<hr/>|</html>)!\n$1!g; s|(</script>)(<img[^>]*>)|\n\t$1\n\t$2|g; s|<br/><a|<br/>\n\t<a|g; s/(<div.*>)(<a)/\1\n\t$2/g; s|></div>|>\n</div>|g; s|</dt><dd|</dt>\n<dd|g; s/>(<h\d>)/>\n$1/g; s|<script(.*js")/>|<script$1></script>\n\t|g; s|<(.*)/>|<$1 />|g; s/^\t+$//g;
build.xml
それでは,このMakefileと同じ動きをするbuild.xmlを作成するまでの迷走の軌跡を公開します.とりあえず,index.xmlとtop.xslからindex.htmlを変換するタスクを記述しました.ちなみに,antでXTを使うためSweet Ant Tools 0.6を使っています.
<project name="xml2html" default="index" basedir="."> <taskdef name="xtask" classname="net.sweetohm.ant.xml.XTask"/> <property name="xsl" value="./xsl"/> <property name="xslt" value="${xsl}/top.xsl"/> <target name="index"> <xtask file="index.xml" style="${xslt}" tofile="index.html"/> </target> </project>
XMLからXHTMLへの変換はうまくいきました.続いて,format.plを使った整形を試みました.
<project name="xml2html" default="index" basedir="."> <target name="index"> <xtask file="index.xml" style="${xslt}" tofile="index_unformatted.html"/> <exec executable="format.pl" output="index.html"> <arg line="index_unformatted.html"/> </exec> <delete file="index_unformatted.html"/> </target> </project>
これを実行すると,以下のようなエラーが発生しました.
$ ant Buildfile: build.xml up-to-date: index: [xtask] Transforming: C:\web\index.xml BUILD FAILED file:c:/web/build.xml:18: Execute failed: java.io.IOException: CreateProcess: ".\xsl\format.pl output=index.html" index_unformatted.html error=2 Total time: 4 seconds
FAQに記述がありました.native unixの場合はスクリプトファイルをそのまま実行可能ですが,cygwinのようなunix-type shellの場合はスクリプトファイルの直接起動はできないようです.以下のように書換えます.
<project name="xml2html" default="index" basedir=".">
<target name="index">
<xtask file="index.xml" style="${xslt}" tofile="index_unformatted.html"/>
<exec executable="perl" output="index.html"> <!-- perl.exeを実行.format.plはperl.exeへの引数 -->
<arg line="format.pl index_unformatted.html"/>
</exec>
<delete file="index_unformatted.html"/>
</target>
</project>
index.xmlからindex_unformatted.htmlを作り,それを整形してindex.htmlを作成した後,index_unformatted.htmlを削除できるようになりました.しかし,この記述の場合,index.htmlがindex.xmlより新しくてもxtaskを毎回実行してしまいます.index_unformatted.htmlを削除しているためです.つまり,以下のxtaskの記述の場合,
<xtask file="index.xml" style="${xslt}" tofile="index_unformatted.html"/>
比較の対象となるのはindex.xmlとindex.htmlではなく,index.xmlとindex_unformatted.htmlとなります.そして,index_unformatted.htmlをXMLからXHTMLへの変換終了後に削除しているため,xtaskを必ず実行してしまうのです.
xtaskに指定するファイルをindex_unformatted.htmlではなく,最終的に残るindex.htmlにしてみました.
<project name="xml2html" default="index" basedir="."> <target name="index"> <xtask file="index.xml" style="${xslt}" tofile="index.html"/> <exec executable="perl" output="index2.html"> <arg line="format.pl index.html"/> </exec> <move file="index2.html" tofile="index.html"/> </target> </project>
xtaskは制御できるようになりましたが,タスクexecとmoveは毎回動いてしまいます.
最終的に,ターゲットindexの前にタスクuptodateを使ってファイルの新旧を判定することにしました.
<project name="xml2html" default="index" basedir="."> <taskdef name="xtask" classname="net.sweetohm.ant.xml.XTask"/> <property name="xsl" value="./xsl"/> <property name="xslt" value="${xsl}/top.xsl"/> <target name="up-to-date"> <uptodate property="isIndexUpToDate" targetfile="index.html"> <srcfiles dir="." includes="index.xml"/> <srcfiles dir="${xsl}" includes="top.xsl"/> </uptodate> </target> <target name="index" depends="up-to-date" unless="isIndexUpToDate"> <xtask file="index.xml" style="${xslt}" tofile="index_unformatted.html"/> <exec executable="perl" output="index.html"> <arg line="${xsl}/format.pl index_unformatted.html"/> </exec> <delete file="index_unformatted.html"/> </target> </project>