2

拡張子が .xhtml の 1000 個のファイルがディレクトリ入力にあり、それらのファイルの特定のサブセット (出力パスが $(FILES) など) を xslt を介してディレクトリ出力の同じ名前のファイルに変換する必要があるとします。簡単な make ルールは次のようになります。

$(FILES): output/%.xhtml : input/%.xhtml
    saxon s:$< o:$@ foo.xslt

もちろん、これは一度に 1 つのファイルを変換することで機能します。問題は、saxon のバッチ処理を使用して一度にすべてのファイルを処理したいということです。これは、ファイルの数を考えると、ファイルごとに Java と saxon をロードするオーバーヘッドを考慮すると、はるかに高速になるためです。Saxon では、-s (ソース) オプションをディレクトリにすることができ、そのディレクトリ内のすべてのファイルを処理し、-o: オプションで指定されたディレクトリに同じ名前の結果を配置します。

パターン ルールを使用して、GNU make に単一のコマンドを実行させ、複数のファイルを更新させるよく知られた手法を認識しています。

output/%.xhtml: input/%.xhtml
    saxon s:input -o:output foo.xslt

しかし、私の場合、これには 2 つの問題があります。まず、変更されたファイルだけでなく、入力ディレクトリ内のすべてのファイルに対して変換を実行します。次に、変換を $(FILES) で指定されたファイルのサブセットに制限しません。パターン ルールで指定されたレシピをすべての一致するターゲットに対して 1 回だけ実行する GNU make 機能は、いわゆる「静的パターン ルール」([こちら] を参照) の場合には機能しません。ポストが知られています。

saxon のバッチ処理機能を使用するには、一時ディレクトリを作成し、処理するファイルのみをそこにコピーしてから、その一時ディレクトリを入力ディレクトリとして変換を実行する必要があります。一時ディレクトリを作成しようとしましたが、後で使用するためにターゲット固有の変数を使用してその名前を覚えています。

$(FILES): TMPDIR:=$(shell mktemp -d)

ただし、これにより、古いターゲットごとに新しい一時ディレクトリが作成されます。いずれにせよ、必要なファイルをそのディレクトリにコピーするルールを構成する方法がわかりません。現在の最上位ターゲットに関連していないものも含め、すべてのメイクファイルを解析する非再帰的なメイクシステムがあるため、メイクファイルが解析されるときに一時ディレクトリを作成したくありません。必要がない/使用されない状況のために一時ディレクトリを作成したい。

単一の入力から複数のファイルを作成することについて、過去にSOで多くの質問が寄せられたことをよく知っています。1 つの解決策は (非静的) パターン ルールです。他のソリューションには、偽のターゲットが含まれます。ただし、この場合、これらすべてをまとめる方法については行き詰まっています。

変更されたファイルを特定し、静的パターン ルールを使用してそれらをコピーできます

$(FILES): output/%.xhtml : input/%.xhtml
    TMPDIR=`mktemp -d`
    cp $< $(TMPDIR)

しかし、実際には、単一の cp コマンドでファイルをコピーすることを好みますが、これはファイルを 1 つずつコピーします。おそらく、ここにいくつかのアプリケーションがありcp -uますか?

また、更新が必要なファイルにアドホック拡張機能を使用することも検討しましたが、これを機能させる方法もわかりませんでした。いずれかのファイルが変更された場合、あきらめて、すべてのファイルに対して saxon 変換を実行しようとしていますが、何か良い方法はありますか?

4

3 に答える 3

1

個人的には、コマンド ラインからこれを実行しようとはしません。これは、私がシェル スクリプトの達人ではないことが一因です。私も Ant ウィザードではありませんが、要件は変更されていないファイルを処理することであるため、これは Ant の領域に非常に当てはまるようです。一方、Ant は変換ごとにスタイルシートを再コンパイルしますが、これは回避したいオーバーヘッドです。その場合、最善の策はおそらく小さな Java アプリケーションを作成することです。おそらく100行以下です。

最後の可能性は、Saxon 内で処理を行うことです。つまり、collection() 関数を使用して複数の入力ファイルを読み取り、xsl:result-document を使用して複数の結果ファイルを生成する単一の変換です。Saxon (商用版) は、処理するファイルをフィルター処理できる拡張機能 last-modified を提供します。1000 個のファイルがある場合、拡張関数 saxon:discard-document() を使用してヒープがいっぱいになるのを防ぐこともできます。

于 2013-02-22T09:18:19.153 に答える
0

ここでの問題の 1 つは、「saxon」がディレクトリ内の 1 つのファイルまたはすべてのファイルをサポートするため、一時ディレクトリにコピーしないとバッチ処理には適していないことだと思います。

それ以外の場合は、タイムスタンプ マーカー ファイルをプロキシ ターゲットとして使用することで、非常に簡単に行うことができます。例えば:

output/.timestamp : $(FILES)
    mkdir -p $(@D)
    $(COMMAND) -outputdir=output $?
    touch $@

3 つのコマンドは次のとおりです。

  1. 出力ディレクトリが存在することを確認してください。
  2. タイムスタンプ ファイルよりも新しいファイルに対してバッチ コマンドを実行します。
  3. タイムスタンプ ファイルを更新します (必要に応じて作成します)。

コマンドの各行は独自のサブシェルで実行され、コマンド行が失敗した場合、後続の行は呼び出されないことに注意してください。

このアプローチは、Java ビルドで役立ちます。

于 2013-07-30T17:22:53.623 に答える
0

個人的には、ファイルごとに 1 つのコンパイラという独自の定式化が気に入っています。-j nこれはmakeのフラグでうまくいきませんか?

もちろん、ファイルをコピーしてバッチ処理し、最後に saxon を実行することもできます。再帰的な make (うーん!) は順序を整理できます。何かのようなもの:

.PHONY: all
all:
    rm -rf tmpdir
    ${MAKE} tmpdir/sentinel
    saxon -s:tmpdir -o:output foo.xslt

tmpdir/sentinel: $(FILES) ; touch $@

$(FILES): output/%.xhtml: input/%.xhtml
    ln $< $(patsubst input/%,tmpdir/%,$<)

これは機能しますが、私は嘘をつくことに非常にうんざりしています (静的パターン ルールは でターゲットを作成すると主張していますoutput/が、実際には でその汚い行為を行いtmpdir/ます)。

のレシピでtmpdir/sentinel$?古い出力ファイルのリストに正しく設定されていることに注意してください。これは、フォルダーではなく saxon に一連のファイルを渡すことができる場合に便利です。

于 2013-02-28T17:04:55.117 に答える