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>