2009/12/30

Anakia 1.0: 出力フォーマットのTips

Anakiaに限らずVelocityを使うと、テンプレートと出力されたファイルの間に予期しない改行コードが埋め込まれるなどの違いが生まれます。 今回はVelocityの MLに投稿された記事を元に対策をメモしておきます。

問題の現象について

MLなどでも度々問題になっているようですが、Velocityでは命令の前に埋め込まれた空白などがそのまま出力されてしまいます。

例えばanakiaを使っているとして、次のようなテンプレートを準備します。

vslテンプレート

<?xml version="1.0" encoding="UTF-8" ?>
<html>
#document()
</html>
#macro (document)
  #set ($allSections = $root.getChildren())
  #foreach ( $section in $allSections )##
    #if ($section.getName().equals("p"))##
    <p>
      $section.getContent()
    </p>
    #end
  #end
#end

出力は次のようになります。

入力ファイル

<?xml version="1.0" ?>

<blog>
  <p>sample messages</p>
</blog>

vslテンプレートを適用した出力例

<?xml version="1.0" encoding="UTF-8" ?>
<html>
            <p>
        sample messages
      </p>
      </html>

期待する出力は、pの開始タグと閉じタグの先頭が縦に揃っていて、内部にコンテンツが少し字下げされて表示されているものなのですが、少し違います。

期待する出力

<?xml version="1.0" encoding="UTF-8" ?>
<html>
      <p>
        sample messages
      </p>
</html>

VTL命令行にある空白の出力抑制

Velocityのテンプレート言語(VTL)の命令はスクリプト言語なので、 書く時には適当にインデントを追加しないと人間には読みずらくなります。

しかし、そのインデントに使われた空白がそのまま出力されてしまうと意図しない空白となる場合があります。

修正版のvslテンプレート

出力をみながらテンプレートを修正します。

修正版 vslテンプレート

<?xml version="1.0" encoding="UTF-8" ?>
<html>
#document()
</html>
#macro (document)
#set ($allSections = $root.getChildren())
#foreach ( $section in $allSections )
#if ($section.getName().equals("p"))
      <p>
        $section.getContent()
      </p>
#end
#end
#end

出力例

<?xml version="1.0" encoding="UTF-8" ?>
<html>
      <p>
        sample messages
      </p>
</html>

出力は意図したようになりましたが、 書かれたテンプレートはかなり人間には読めないものになってしまいました。

vslファイルの自動生成

人間に読めなくて大変なら、人間が編集するファイルとanakiaが使うファイルを分ければ良いという発送で、'#'で始まる行は先頭の空白を取り除くようにしようと思います。

build.xmlは次のようになっていて、 prop/blog.vsl ファイルを自動生成します。

build.xmlファイルから抜粋

<anakia basedir="${docs.src}" 
   destdir="${docs.dest}"
   extension=".html"
   style="prop/blog.vsl"

簡単にできるのでMakefileを使う事にしました。

Makefileの内容

all: prop/blog.vsl build

prop/blog.vsl: prop/blog.vsl.template
	sed -e 's/^ *#/#/' $< > $@

build:
	ant -f prop/build.xml

blog.vsl.template はインデントを使って編集して、makeコマンドで blog.vsl を生成しています。 Makefileに限定する必要もないのですが、 blog.vslblog.vsl.template より新しい場合には生成過程がスキップされるので無駄が省く事ができます。 大した時間じゃないですけどね。

改行コードの出力を抑制する

さて今回使ったのは簡単な例ですが、場合によっては本来1行に収めたいものを複数行に渡って書きたい場合があるかもしれません。 その場合には"##"を行末に入れる事で、改行の出力を抑制する事ができます。

vslテンプレート

<?xml version="1.0" encoding="UTF-8" ?>
<html>
#document()
</html>
#macro (document)
  #set ($allSections = $root.getChildren())
  #foreach ( $section in $allSections )
    #if ($section.getName().equals("p"))
      <p>##
        $section.getContent()##
      </p>
    #end
  #end
#end

改行を抑制した例

<?xml version="1.0" encoding="UTF-8" ?>
<html>
      <p>        sample messages      </p>
</html>

これはp開始タグと getContent() が出力された後の改行が抑制されています。 sample messages前後の空白を抑制したい場合には次の2つのパターンが考えられると思います。

例1

      <p>$section.getContent()</p>

例2

      <p>##
$section.getContent()##
</p>

まとめ

今回は2つのTipsを書きましたが、Velocityを使うと出力されるHTMLコードが汚なくなると感じた場合には有効だと思います。

これぐらいならVelocityのTutorialにあっても良さそうなものですが、 知らないとどうしようもないですよね…。 出力に気を配る人はそんなにいないのかなぁ。

0 件のコメント: