Hatena::ブログ(Diary)

xmallocのプログラミングノート

2010年07月13日

DOMモジュールをテンプレートエンジン代わりに使う三つの利点+1

PHP5からPHP標準添付のDOMモジュールもlibxml2ベースのものになって、htmlも処理できるようになったのでだいぶ使いやすくなったと思う。DOMを使うと文書構造にアクセスして編集できるので、テンプレートエンジンの代わりとしてそれなりに利用されてても良いと思うんだけど少なくとも個人的観測範囲内だと全ったくもって流行ってなかったりして*1大変残念なので、PHPDOMモジュールテンプレートエンジン代わりに使う利点をまとめてみました。



1.インスコ不要

最初に書いたけど、PHP5のDOMモジュールインスコしなくても標準で使える。もう少し具体的に言うと--disable-dom configureオプションを付けてビルドしてなかったら使える、ってことなのでその辺のレン鯖でも普通は動くので便利です。

インスコ不要なものはデプロイするときに「あれ入れた?」「忘れたー」「あれは入れた?」「忘れたー」「あっちは」「うーん知らない」「氏ね」ループに陥らなくて精神的に大変よろしいと思います。



2.デザイナー/コーダーへの説明が楽

どのテンプレートエンジンにしろ、だいたいそれ用の構文があったりします。無いやつもあるけどだいたいあります。特にSmartyとか人気のやつはだいたいあります。

いずれにしてもテンプレートエンジンを使うとなったら、「ここはテンプレートエンジンの構文なんで変えないでくださいね」「そこも同じなんで以下同文」「あーそれも同じなんで以下同文」「だからそこ変えるんじゃねーよボケ」という不毛な説明を延々と繰り返すハメになることを覚悟する必要がある。世の中には大変素晴らしい企業さんもあるようで、そういう説明が要らないところもあるみたいですが、うち場合デザイナーがいない上、デザイナー/コーダー=お客さんってプロジェクトが大半なので、単に可否の問題でなく営業的な問題であまりこの辺を強く言えない事情もあったりします。なので物分かりのあまり良くないお客さんの場合は延々と不毛な説明するとかえってややこしいので、htmlもらってこっちでテンプレートに変換する退屈な作業を延々と繰り返してます。

でもDOMなら不毛な説明も退屈な作業も不要。id属性とかclass属性とか、テンプレートとして使用する要素がhtmlそのものなので向こうも分かるはず。さすがにこの程度も分からない奴とは一緒に仕事できないのです。



3.DOMなんで覚えるのも簡単

DOMなんでJavaScriptかじってたら多少は知ってるはず・・・て言うかウェブ関係のプログラミングやってれば知らないのはかなり問題。知らんと思ってる人もgetElementByIdとかcreateElementとかがDOMだと言われれば「へぇー、これって2年くらい前に流行ってたよね、2年くらい前に見たわ」と返事してくれることでしょう。

という感じでたぶんDOM自体は知ってると思うので、簡単なサンプルも載せときます。


まずテンプレートとしてexam1.htmlを作ります。モジュールの仕様の関係で、doctypeとmetaタグによるcharsetの指定を省略すると挙動が変わるので省略しないように。

<!doctype HTML>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  </head>
  <body>
    <div id="message"></div>
  </body>
</html>

次にexam1.htmlを読み込んでid="message"のdivの中身を"あいうえお"に書き換えるスクリプトを作ります。

<?php
$doc = new DOMDocument();
$doc->loadHTMLFile("exam1.html");
$message = $doc->getElementById("message");
$message->appendChild($doc->createTextNode("あいうえお"));
echo $doc->saveHtml();
?>

このスクリプトを動かすと以下の出力が得られます。

<!DOCTYPE HTML>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head>
<body>
    <div id="message">あいうえお</div>
  </body>
</html>

ところどころ改行とスペースが詰められるは、まあそういう仕様なんで諦めてください。スペース入れたいときは&nbsp;使った方が良いですよ、ということです。

もっと詳しいことはPHP: DOM - Manualからどうぞ。



+1.ドキュメントに直接アクセスできる

うちだけの話かもしれないので+1にしたけど、例えばhtmlフォームのラベルとか、ユーザーなんだかデザイナーなんだかよく分からない人が適当にいじくりたいという要望がたまにあります。それでまあフォームの場合、そのラベルをエラーメッセージに埋め込みたいとか言う話になるので、コンフィギュレーションファイルを用意したり結局プログラムで二重持ちしたりしてることがありますが、色々なやましい問題がこの辺で噴出します。

そこでDOMの出番ですよ、と。テンプレートDOMにしとけば、htmlから適当な要素の値を抜いてくれば良いだけですので、この手の問題は全部解決です。


例えばこんな感じのexam2.htmlがあって、

<!doctype HTML>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p id="error" style="display:none"></p>
    <form method="post">
      <label for="username">ユーザー</label>
      <input type="text" id="username" name="username" />
      <input type="submit" />
    </form>
  </body>
</html>

usernameが未入力ならlabelを含んだエラーメッセージを表示する場合はこんなスクリプトで解決できます。

<?php
$doc = new DOMDocument();
$doc->loadHTMLFile("exam2.html");
if (isset($_POST['username']) && !$_POST['username']) {
    $username = $doc->getElementById('username');
    $labels = $doc->getElementsByTagName('label');
    for ($i = 0; $i < count($labels); $i++) {
        $label = $labels->item($i);
        if ($label->getAttribute('for') == $username->getAttribute('id')) {
            $mesg = "{$label->textContent}が未入力です。";
            $error = $doc->getElementById('error');
            $error->removeAttribute('style');
            $error->appendChild($doc->createTextNode($mesg));
            break;
        }
    }
}
echo $doc->saveHtml();
?>

エラーメッセージを含む出力はこんな感じ。ちゃんとメッセージにlabel for="username"の値が表示されます。

<!DOCTYPE HTML>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head>
<body>
    <p id="error">ユーザーが未入力です。</p>
    <form method="post">
      <label for="username">ユーザー</label>
      <input type="text" id="username" name="username"><input type="submit">
</form>
  </body>

</html>


ということで、騙されたと思って一度騙されてください。

*1DOMテンプレート代わりに使うといったことを書いてるブログは確認してますが、流行ってないってところに力点置いてます

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/xmalloc/20100713/1278996453