Hatena::ブログ(Diary)

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

2010年08月02日

GIGAZINEの求人募集ほど高らかに自らブラック企業であることを宣言するものを他に知らない

はてブでも叩かれてるのでご存知の方も多いと思いますが、【求人募集】GIGAZINEのために働いてくれる記者・編集を募集します - GIGAZINEの内容が超絶ブラックです。

「払われた金の分だけしか働かない、働きたくない、記事を書くのは面倒くさい、そもそもできれば書きたくない」という風潮が編集部内に蔓延し、そのことを明言する者さえ現れました。


(中略)


確かに会社が研修を行い、勉強のための時間と費用を負担する、そういうのもありかもしれませんが、GIGAZINEは10人程度の小さなところなので一日たりとも休むわけにはいかず、大企業のような充実したサービスはそもそも提供できないのです。どちらかというとベンチャー企業と同じです。しかし、「一流の会社と同じような労使関係を結んで雇用主と労働者の対等な関係を結ばなくてはならない。働いた分だけの給料はもらわなくては!」というような動きが出るにいたり、もはや我慢の限界を超えたというのが正直なところです。


(太字原文まま)

【求人募集】GIGAZINEのために働いてくれる記者・編集を募集します - GIGAZINE

要約すると「金は払いたくないけど死ぬまで働け」って感じでしょうか。ブラック企業経営者も何人か知ってますがここまできっぱりと金を払いたくないと言ってる人は知りません。あまり給料を出せなくて申し訳ないと言いつつサビ残とかさせてるところがほとんどです・・・建前でしょうけど、建前があるだけマシ。


GIGAZINEで記事を書くというのは決して肉体労働ではなく、自己実現を兼ねている知的作業のはずなのですが、ただの「労働」として捉えているような者との価値観の落差に私がもはや耐えられず、なおかつ読者に提供される記事の質の低下も目に余るものが出ているため、次のような方針転換に至りました。

【求人募集】GIGAZINEのために働いてくれる記者・編集を募集します - GIGAZINE

単純に時間比で労働量が計りにくいという意味で、知識労働と肉体労働は違うかもしれません。ただだからといって金をくれと言う権利が知識労働者に無い訳ではありません。むしろ計測が難しいからこそ、労働者側から積極的に自らのの成果を経営者に認めさせ、賃金交渉を行っていく必要があると思います。(どちらかと言うと知識労働を成果で計らずに時間単価で計り(ついでにサビ残させて)人件費を抑えている企業の方が多いですし。)


また、面接の時点では嘘のキレイゴトを並べ立て、どのような業務命令にも従うようなことを言っておきながら、実際にはあれがいや、これがいや、あれはできない、これはできない、そのようなことには興味がないからほかの人にやってもらってくれ、挙げ句の果てには好きなヤツが好きなようにすればいいだけであって、働けば働くほど損をする、あれもしてくれない、これもしてくれないというようなことまで言われるようになってしまいました。


(中略)


当然、採用してから面接などで言っていたことが「虚偽」であるということが判明した場合は即刻、やめてもらうことになります。自分を良く見せて嘘をついて GIGAZINEに入った人、要するに、「GIGAZINEで働くべきではない人」は基本的にアウトだと考えてもらって結構です。

【求人募集】GIGAZINEのために働いてくれる記者・編集を募集します - GIGAZINE

業務命令として「死ね」と言ったら死ぬことを期待してんでしょうか。なんか小学生みたいですね。本文を拝見する限り労働基準法に違反した業務命令を出してる/もしくは業務命令を出さずにそういった行動をしてくれるのを期待しているようですので、そもそも労働者に従う義務があると思えません。


ニュースサイトで記事を書くというのは、普通の労働とは絶対に違うのだ!」ということを事前にちゃんと理解していただきたいのです。


(太字原文まま)

【求人募集】GIGAZINEのために働いてくれる記者・編集を募集します - GIGAZINE

ニュースサイトでの労働は尊いもの、それ以外の労働は下賎なもの、という感じでしょうか。下賎な仕事しててどうもすみません。

上から目線で煽りながらどうでも良いことを垂れ流すのがマスゴミ様の尊いお仕事ですよね。単なる求人募集記事なのにニュースサイトで働いてない人全員を軽くdisっちゃうなんてさすがです。惚れちゃいそうです。ありがとうございました。

2010年08月01日

Twitter APIから取得したテキストをHTMLに変換するための公式ライブラリ

Twitter statuses/public_timeline APIとか、ツイートを取得する系のAPIのデータから@とか#とかhttp://をURLに変換する公式ライブラリがあるようなので簡単にレポ。

まずライブラリ自体は以下のURLからダウンロードできる。

mzsanford's twitter-text-rb at master - GitHub

mzsanford's twitter-text-java at master - GitHub

mzsanford's twitter-text-php at master - GitHub

Python Package Index : twitter-text-py 1.0.3

Tweet Entities | dev.twitter.comにツイートからエンティティ抜き出すにはtwitter-text使えって書いてるからこれらが公式ってことでほぼ問題無いと思う。mzsanford氏はツイッターの国際化チームの一員。ただしPythonは作者違うようなので公式扱いでは無いかもしれない。Perlは無いっぽい。



使い方

Ruby版が大元っぽかったのでそっちの使い方説明しようと思ったんだけど、rakeの動かし方がいまいちよく分からんかった(何かファイルが無いと怒られた)ので、PHP版で説明。(個人的にはPython版が一番要るんだけど作者違うのでアレ。)

  1. mzsanford's twitter-text-php at master - GitHubからリポジトリをcloneしてダウンロード
    $ git clone http://github.com/mzsanford/twitter-text-php.git
    
  2. リポジトリ中のsrc/Twitterをinclude_pathの通ったディレクトリにコピー。
    $ cd twitter-text-php/src
    $ cp -r Twitter WHERE
    
  3. Twitter_Autolinkクラスのautolinkメソッドで、APIから取得したテキストをHTMLに変換できる。
    <?php
    require_once "Twitter/Autolink.php";
    $a = new Twitter_Autolink();
    echo $a->autolink('RT @mashable @LinkedIn Beefs Up Its Twitter Integration [PICS] http://bit.ly/bkB7cA #linkedin #tweets #twitter'), "\n";
    ?>
    
    出力はこんな感じ。スクリーンネームハッシュタグURLが<a>タグでリンクになってる。
    RT @<a class="tweet-url username" href="http://twitter.com/mashable">mashable</a> @<a class="tweet-url username" href="http://twitter.com/LinkedIn">LinkedIn</a> Beefs Up Its Twitter Integration [PICS] <a href="http://bit.ly/bkB7cA">http://bit.ly/bkB7cA</a> <a href="http://twitter.com/search?q=%23linkedin" title="#linkedin" class="tweet-url hashtag">#linkedin</a> <a href="http://twitter.com/search?q=%23tweets" title="#tweets" class="tweet-url hashtag">#tweets</a> <a href="http://twitter.com/search?q=%23twitter" title="#twitter" class="tweet-url hashtag">#twitter</a>
    
    ちなみに$Twitter_Autolink->noFollowで<a>タグにnofollow属性付けれるってソースに書いてあるんだけどPHP版は実装されてないっぽい。有効にしたかったら要改造。

Githubにも使い方が書いてあるのでそっちも見てくれ・・・まあそれ紹介すれば済む話なんだけど。

他の言語のは誰か親切な人が説明してくれるはず。



後書き

不勉強ながらこのライブラリの存在自体知らなかったりしました。Tweet Entities | dev.twitter.comを読んでたらたまたま見つけた感じです。twitter-text-rbとかでググるとそれなりに使ってる人いるみたいですが、普及してるとは言い難い感じ。

とりあえず、一時期あった日本語ハッシュタグとかの公式変換ルールがいまいちよく分からん問題とかはこれ一発で解決ですよ、ということで。

2010年07月29日

MySQLにインストールされたCHARACTER SETとCOLLATIONの確認方法とカラム別の設定方法

MySQLはVARCHAR型のカラムに対して、(CREATE DATABASE等で指定された)デフォルトのキャラクタセットと照合順序を使用して文字列検索を行います。

CREATE DATABASE mydb DEFAULT CHARACTER SET utf8;

上のように定義したデータベースのキャラクタセットはutf8となり、照合順序はutf8_general_ciとなります。

噛み砕いて言うと、このデータベースではデフォルトでVARCHAR等のカラムのキャラクタセットはutf8となり、utf8なので1文字のサイズは3バイトとなり、文字列型カラムの比較では大文字小文字を区別しなくなります。(_ciはcase insensitiveの略です。)



だいたいの場合上の設定で問題無いですが、たまにカラムごとにキャラクタセットと照合順序を変更したくなります。

例えばVARCHARカラムにエスケープ済みURLを保存したい場合、1文字3バイトは冗長です。インデクスを使用する場合MySQLの制限でインデクス列の合計サイズが1000バイト以下でないといけないので、utf8のままですとVARCHAR(333)あたりが上限となり、URLを保存するカラムとしては微妙に短い気がします。また大文字小文字を区別しないのもURLとしては問題ありです。

で、カラムごとにキャラクタセットと照合順序を変更するにはCHARACTER SETとCOLLATE構文を使用します。例の続きで、URL用カラムならこんな感じにしてます。

CREATE TABLE url_data
(url VARCHAR(1000) CHARACTER SET ascii COLLATE ascii_bin);

ちなみにテーブル単位でキャラクタセットと照合順序を指定することもできますが使ったことないです。

CREATE TABLE url_data
(url VARCHAR(1000))
CHARACTER SET ascii COLLATE ascii_bin;


キャラクタセットと照合順序を変更するには、それぞれサーバで指定可能な値を調べる必要があります。

ログインしているMySQLデータベースでどういったキャラクタセットがサポートされているかは、SHOW CHARACTER SET命令で確認できます。Default collationがそのキャラクタセットのデフォルト照合順序です。COLLATEを指定せずにCHARACTER SETだけ指定するとDefault collationが照合順序となります。

mysql> SHOW CHARACTER SET;
+----------+-----------------------------+---------------------+--------+
| Charset  | Description                 | Default collation   | Maxlen |
+----------+-----------------------------+---------------------+--------+
| big5     | Big5 Traditional Chinese    | big5_chinese_ci     |      2 | 
| dec8     | DEC West European           | dec8_swedish_ci     |      1 | 
| cp850    | DOS West European           | cp850_general_ci    |      1 | 
| hp8      | HP West European            | hp8_english_ci      |      1 | 
| koi8r    | KOI8-R Relcom Russian       | koi8r_general_ci    |      1 | 
| latin1   | cp1252 West European        | latin1_swedish_ci   |      1 | 
| latin2   | ISO 8859-2 Central European | latin2_general_ci   |      1 | 
| swe7     | 7bit Swedish                | swe7_swedish_ci     |      1 | 
| ascii    | US ASCII                    | ascii_general_ci    |      1 | 
| ujis     | EUC-JP Japanese             | ujis_japanese_ci    |      3 | 
| sjis     | Shift-JIS Japanese          | sjis_japanese_ci    |      2 | 
| hebrew   | ISO 8859-8 Hebrew           | hebrew_general_ci   |      1 | 
| tis620   | TIS620 Thai                 | tis620_thai_ci      |      1 | 
| euckr    | EUC-KR Korean               | euckr_korean_ci     |      2 | 
| koi8u    | KOI8-U Ukrainian            | koi8u_general_ci    |      1 | 
| gb2312   | GB2312 Simplified Chinese   | gb2312_chinese_ci   |      2 | 
| greek    | ISO 8859-7 Greek            | greek_general_ci    |      1 | 
| cp1250   | Windows Central European    | cp1250_general_ci   |      1 | 
| gbk      | GBK Simplified Chinese      | gbk_chinese_ci      |      2 | 
| latin5   | ISO 8859-9 Turkish          | latin5_turkish_ci   |      1 | 
| armscii8 | ARMSCII-8 Armenian          | armscii8_general_ci |      1 | 
| utf8     | UTF-8 Unicode               | utf8_general_ci     |      3 | 
| ucs2     | UCS-2 Unicode               | ucs2_general_ci     |      2 | 
| cp866    | DOS Russian                 | cp866_general_ci    |      1 | 
| keybcs2  | DOS Kamenicky Czech-Slovak  | keybcs2_general_ci  |      1 | 
| macce    | Mac Central European        | macce_general_ci    |      1 | 
| macroman | Mac West European           | macroman_general_ci |      1 | 
| cp852    | DOS Central European        | cp852_general_ci    |      1 | 
| latin7   | ISO 8859-13 Baltic          | latin7_general_ci   |      1 | 
| cp1251   | Windows Cyrillic            | cp1251_general_ci   |      1 | 
| cp1256   | Windows Arabic              | cp1256_general_ci   |      1 | 
| cp1257   | Windows Baltic              | cp1257_general_ci   |      1 | 
| binary   | Binary pseudo charset       | binary              |      1 | 
| geostd8  | GEOSTD8 Georgian            | geostd8_general_ci  |      1 | 
| cp932    | SJIS for Windows Japanese   | cp932_japanese_ci   |      2 | 
| eucjpms  | UJIS for Windows Japanese   | eucjpms_japanese_ci |      3 | 
+----------+-----------------------------+---------------------+--------+
36 rows in set (0.00 sec)

照合順序の確認はSHOW COLLATIONです。_ciで終わるCollationはcase insensitive比較、_binで終わるCollationがバイナリとして比較です。MySQL4とかだと_csで終わる照合順序もあったと思いますが、5.1だと無いっぽいです。

mysql> SHOW COLLATION;
+----------------------+----------+-----+---------+----------+---------+
| Collation            | Charset  | Id  | Default | Compiled | Sortlen |
+----------------------+----------+-----+---------+----------+---------+
| big5_chinese_ci      | big5     |   1 | Yes     | Yes      |       1 | 
| big5_bin             | big5     |  84 |         | Yes      |       1 | 
| dec8_swedish_ci      | dec8     |   3 | Yes     | Yes      |       1 | 
| dec8_bin             | dec8     |  69 |         | Yes      |       1 | 
| cp850_general_ci     | cp850    |   4 | Yes     | Yes      |       1 | 
| cp850_bin            | cp850    |  80 |         | Yes      |       1 | 
| hp8_english_ci       | hp8      |   6 | Yes     | Yes      |       1 | 
| hp8_bin              | hp8      |  72 |         | Yes      |       1 | 
| koi8r_general_ci     | koi8r    |   7 | Yes     | Yes      |       1 | 
| koi8r_bin            | koi8r    |  74 |         | Yes      |       1 | 
| latin1_german1_ci    | latin1   |   5 |         | Yes      |       1 | 
| latin1_swedish_ci    | latin1   |   8 | Yes     | Yes      |       1 | 
| latin1_danish_ci     | latin1   |  15 |         | Yes      |       1 | 
| latin1_german2_ci    | latin1   |  31 |         | Yes      |       2 | 
| latin1_bin           | latin1   |  47 |         | Yes      |       1 | 
| latin1_general_ci    | latin1   |  48 |         | Yes      |       1 | 
| latin1_general_cs    | latin1   |  49 |         | Yes      |       1 | 
| latin1_spanish_ci    | latin1   |  94 |         | Yes      |       1 | 
| latin2_czech_cs      | latin2   |   2 |         | Yes      |       4 | 
| latin2_general_ci    | latin2   |   9 | Yes     | Yes      |       1 | 
| latin2_hungarian_ci  | latin2   |  21 |         | Yes      |       1 | 
| latin2_croatian_ci   | latin2   |  27 |         | Yes      |       1 | 
| latin2_bin           | latin2   |  77 |         | Yes      |       1 | 
| swe7_swedish_ci      | swe7     |  10 | Yes     | Yes      |       1 | 
| swe7_bin             | swe7     |  82 |         | Yes      |       1 | 
| ascii_general_ci     | ascii    |  11 | Yes     | Yes      |       1 | 
| ascii_bin            | ascii    |  65 |         | Yes      |       1 | 
| ujis_japanese_ci     | ujis     |  12 | Yes     | Yes      |       1 | 
| ujis_bin             | ujis     |  91 |         | Yes      |       1 | 
| sjis_japanese_ci     | sjis     |  13 | Yes     | Yes      |       1 | 
| sjis_bin             | sjis     |  88 |         | Yes      |       1 | 
| hebrew_general_ci    | hebrew   |  16 | Yes     | Yes      |       1 | 
| hebrew_bin           | hebrew   |  71 |         | Yes      |       1 | 
| tis620_thai_ci       | tis620   |  18 | Yes     | Yes      |       4 | 
| tis620_bin           | tis620   |  89 |         | Yes      |       1 | 
| euckr_korean_ci      | euckr    |  19 | Yes     | Yes      |       1 | 
| euckr_bin            | euckr    |  85 |         | Yes      |       1 | 
| koi8u_general_ci     | koi8u    |  22 | Yes     | Yes      |       1 | 
| koi8u_bin            | koi8u    |  75 |         | Yes      |       1 | 
| gb2312_chinese_ci    | gb2312   |  24 | Yes     | Yes      |       1 | 
| gb2312_bin           | gb2312   |  86 |         | Yes      |       1 | 
| greek_general_ci     | greek    |  25 | Yes     | Yes      |       1 | 
| greek_bin            | greek    |  70 |         | Yes      |       1 | 
| cp1250_general_ci    | cp1250   |  26 | Yes     | Yes      |       1 | 
| cp1250_czech_cs      | cp1250   |  34 |         | Yes      |       2 | 
| cp1250_croatian_ci   | cp1250   |  44 |         | Yes      |       1 | 
| cp1250_bin           | cp1250   |  66 |         | Yes      |       1 | 
| gbk_chinese_ci       | gbk      |  28 | Yes     | Yes      |       1 | 
| gbk_bin              | gbk      |  87 |         | Yes      |       1 | 
| latin5_turkish_ci    | latin5   |  30 | Yes     | Yes      |       1 | 
| latin5_bin           | latin5   |  78 |         | Yes      |       1 | 
| armscii8_general_ci  | armscii8 |  32 | Yes     | Yes      |       1 | 
| armscii8_bin         | armscii8 |  64 |         | Yes      |       1 | 
| utf8_general_ci      | utf8     |  33 | Yes     | Yes      |       1 | 
| utf8_bin             | utf8     |  83 |         | Yes      |       1 | 
| utf8_unicode_ci      | utf8     | 192 |         | Yes      |       8 | 
| utf8_icelandic_ci    | utf8     | 193 |         | Yes      |       8 | 
| utf8_latvian_ci      | utf8     | 194 |         | Yes      |       8 | 
| utf8_romanian_ci     | utf8     | 195 |         | Yes      |       8 | 
| utf8_slovenian_ci    | utf8     | 196 |         | Yes      |       8 | 
| utf8_polish_ci       | utf8     | 197 |         | Yes      |       8 | 
| utf8_estonian_ci     | utf8     | 198 |         | Yes      |       8 | 
| utf8_spanish_ci      | utf8     | 199 |         | Yes      |       8 | 
| utf8_swedish_ci      | utf8     | 200 |         | Yes      |       8 | 
| utf8_turkish_ci      | utf8     | 201 |         | Yes      |       8 | 
| utf8_czech_ci        | utf8     | 202 |         | Yes      |       8 | 
| utf8_danish_ci       | utf8     | 203 |         | Yes      |       8 | 
| utf8_lithuanian_ci   | utf8     | 204 |         | Yes      |       8 | 
| utf8_slovak_ci       | utf8     | 205 |         | Yes      |       8 | 
| utf8_spanish2_ci     | utf8     | 206 |         | Yes      |       8 | 
| utf8_roman_ci        | utf8     | 207 |         | Yes      |       8 | 
| utf8_persian_ci      | utf8     | 208 |         | Yes      |       8 | 
| utf8_esperanto_ci    | utf8     | 209 |         | Yes      |       8 | 
| utf8_hungarian_ci    | utf8     | 210 |         | Yes      |       8 | 
| ucs2_general_ci      | ucs2     |  35 | Yes     | Yes      |       1 | 
| ucs2_bin             | ucs2     |  90 |         | Yes      |       1 | 
| ucs2_unicode_ci      | ucs2     | 128 |         | Yes      |       8 | 
| ucs2_icelandic_ci    | ucs2     | 129 |         | Yes      |       8 | 
| ucs2_latvian_ci      | ucs2     | 130 |         | Yes      |       8 | 
| ucs2_romanian_ci     | ucs2     | 131 |         | Yes      |       8 | 
| ucs2_slovenian_ci    | ucs2     | 132 |         | Yes      |       8 | 
| ucs2_polish_ci       | ucs2     | 133 |         | Yes      |       8 | 
| ucs2_estonian_ci     | ucs2     | 134 |         | Yes      |       8 | 
| ucs2_spanish_ci      | ucs2     | 135 |         | Yes      |       8 | 
| ucs2_swedish_ci      | ucs2     | 136 |         | Yes      |       8 | 
| ucs2_turkish_ci      | ucs2     | 137 |         | Yes      |       8 | 
| ucs2_czech_ci        | ucs2     | 138 |         | Yes      |       8 | 
| ucs2_danish_ci       | ucs2     | 139 |         | Yes      |       8 | 
| ucs2_lithuanian_ci   | ucs2     | 140 |         | Yes      |       8 | 
| ucs2_slovak_ci       | ucs2     | 141 |         | Yes      |       8 | 
| ucs2_spanish2_ci     | ucs2     | 142 |         | Yes      |       8 | 
| ucs2_roman_ci        | ucs2     | 143 |         | Yes      |       8 | 
| ucs2_persian_ci      | ucs2     | 144 |         | Yes      |       8 | 
| ucs2_esperanto_ci    | ucs2     | 145 |         | Yes      |       8 | 
| ucs2_hungarian_ci    | ucs2     | 146 |         | Yes      |       8 | 
| cp866_general_ci     | cp866    |  36 | Yes     | Yes      |       1 | 
| cp866_bin            | cp866    |  68 |         | Yes      |       1 | 
| keybcs2_general_ci   | keybcs2  |  37 | Yes     | Yes      |       1 | 
| keybcs2_bin          | keybcs2  |  73 |         | Yes      |       1 | 
| macce_general_ci     | macce    |  38 | Yes     | Yes      |       1 | 
| macce_bin            | macce    |  43 |         | Yes      |       1 | 
| macroman_general_ci  | macroman |  39 | Yes     | Yes      |       1 | 
| macroman_bin         | macroman |  53 |         | Yes      |       1 | 
| cp852_general_ci     | cp852    |  40 | Yes     | Yes      |       1 | 
| cp852_bin            | cp852    |  81 |         | Yes      |       1 | 
| latin7_estonian_cs   | latin7   |  20 |         | Yes      |       1 | 
| latin7_general_ci    | latin7   |  41 | Yes     | Yes      |       1 | 
| latin7_general_cs    | latin7   |  42 |         | Yes      |       1 | 
| latin7_bin           | latin7   |  79 |         | Yes      |       1 | 
| cp1251_bulgarian_ci  | cp1251   |  14 |         | Yes      |       1 | 
| cp1251_ukrainian_ci  | cp1251   |  23 |         | Yes      |       1 | 
| cp1251_bin           | cp1251   |  50 |         | Yes      |       1 | 
| cp1251_general_ci    | cp1251   |  51 | Yes     | Yes      |       1 | 
| cp1251_general_cs    | cp1251   |  52 |         | Yes      |       1 | 
| cp1256_general_ci    | cp1256   |  57 | Yes     | Yes      |       1 | 
| cp1256_bin           | cp1256   |  67 |         | Yes      |       1 | 
| cp1257_lithuanian_ci | cp1257   |  29 |         | Yes      |       1 | 
| cp1257_bin           | cp1257   |  58 |         | Yes      |       1 | 
| cp1257_general_ci    | cp1257   |  59 | Yes     | Yes      |       1 | 
| binary               | binary   |  63 | Yes     | Yes      |       1 | 
| geostd8_general_ci   | geostd8  |  92 | Yes     | Yes      |       1 | 
| geostd8_bin          | geostd8  |  93 |         | Yes      |       1 | 
| cp932_japanese_ci    | cp932    |  95 | Yes     | Yes      |       1 | 
| cp932_bin            | cp932    |  96 |         | Yes      |       1 | 
| eucjpms_japanese_ci  | eucjpms  |  97 | Yes     | Yes      |       1 | 
| eucjpms_bin          | eucjpms  |  98 |         | Yes      |       1 | 
+----------------------+----------+-----+---------+----------+---------+
126 rows in set (0.00 sec)


以上、使用頻度が少なくてよく忘れるのでブログにメモでした。

より詳しくはMySQL :: MySQL 5.1 リファレンスマニュアル :: 9.3 デフォルトのキャラクタセットおよび照合順序の指定をどうぞ。

2010年07月26日

ブログ書けない病

というのにかかったようです。途中まで書いた下書きが結構溜まってますが、なんとなく公開する気になれません。

そんだけ。

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テンプレート代わりに使うといったことを書いてるブログは確認してますが、流行ってないってところに力点置いてます