HTMLを分割して再利用する
shimizukawa
nekoオブジェクトはdtml-varで呼び出すことで<img>タグを生成しましたが、Imageオブジェクト以外でも同様の仕組みを持っているオブジェクトがいくつかあり、 DTML Document や DTML Method もそのうちの一つです。
DTMLでページを分割・再利用する
まずは例として、 standard_html_header, standard_html_footer を読み込んでみます。これらは他のページから使われることを想定してZopeが最初から用意してくれているDTML Methodです(DTML Documentとの違いは後述します)。
さっそくindex_htmlを以下のように書き換えてみてください:
<dtml-var standard_html_header>
<h1><dtml-var title></h1>
<ul>
<li><dtml-var id></li>
<li><dtml-var title></li>
<li><dtml-var title_or_id></li>
<li><dtml-var absolute_url></li>
<li><dtml-var bobobase_modification_time></li>
</ul>
<dtml-var neko>
<dtml-var standard_html_footer>
先頭から<body>までと、</body>から最終行までを置き換えました。viewで表示してみると、これまでと同様に表示されるはずです。しかし、一部のブラウザでは文字化けするようになってしまうと思います。これは、standard_html_headerがこれまでのindex_htmlに記述していた以下の行を出力していないためです:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
この問題を修正するため、standard_html_headerの記述を確認してみましょう。ZMIで確認してみてください。以下のソースが書かれていると思います:
<html> <head><title>&dtml-title_or_id;</title></head> <body bgcolor="#FFFFFF">
新しいdtmlの記述方法が出てきました。ここで使われている &dtml-title_or_id; は <dtml-var title_or_id> と同義です。HTMLの文字実体参照と同じ文法で & で始まって ; で終わっています。
それではstandard_html_headerにmetaタグを追加しましょう:
<html>
<head>
<title>&dtml-title_or_id;</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body bgcolor="#FFFFFF">
ここで、先ほど学んだ獲得を用いて、ルートフォルダに設定したmanagement_page_charsetの値を利用するようにしてみましょう。metaタグを以下のように書き換えます:
<meta http-equiv="Content-Type" content="text/html; charset=<dtml-var management_page_charset>">
これでももちろんOKですが、metaタグの中にdtmlタグが書かれるのはHTML的に微妙な感じがします。そこで &dtml-...; を使って以下のように書き換えます:
<meta http-equiv="Content-Type" content="text/html; charset=&dtml-management_page_charset;">
これで、どのページからも利用できるstandard_html_headerの用意が出来ました。standard_html_headerにサイト全体で共有したい内容を書いておくことで、ページ毎に毎回同じような内容を記述しなくても良いようになります。
standard_html_footerも同じように利用できますので、以下のように書き換えてみましょう:
<hr> LastModified: <dtml-var bobobase_modification_time> </body> </html>
viewで出力結果を確認してみてください。だんだんそれらしくなってきたと思いませんか?
Note
DTMLの記述方法には4つの種類があります。
- <dtml-var title_or_id>
- &dtml-title_or_id;
- <dtml-var expr="title_or_id()">
- <dtml-var "title_or_id()">
1,2は同義、3,4も同義です。3,4の記述方法はPython式を記述する場合の書き方で、プロパティーの取得(titleなど)と関数呼び出し(idやtitle_or_idなど)を明示的に書き分ける必要があります。手間が増える分細かい制御が出来るため、 <dtml-var expr="absolute_url().split('/')"> といった関数呼び出しが可能です。
HTML4.0 strict?やXHTMLとして見たときに正しいのは2と3ですが、DTMLはHTMLに変換されるため出力結果は文法違反にはなりません。とはいえ、普段から文法を気にした方が良いのは確かだし、DreamWeaverなどのツールを使用する場合には正しい文法で記述しておく事が必要になるでしょう。
DTML DocumentとDTML Methodの違い
index_htmlがDTML Documentだったのに対して、standard_html_header,footerはDTML Methodです。これらの違いは何でしょうか?比較のためにそれぞれの編集画面を表示してみましょう。
それぞれの編集画面をよく見比べてみると、タブの数に違いがあります。DTML Documentには Properties タブがありますが、DTML Methodにはありません。DTML Method自身はプロパティーを持てないため、プロパティーを編集するためのタブが用意されていないのです。
ここで、standard_html_headerのコードに <title>&dtml-title_or_id;</title> が利用されていた事を思い出してください。もし、standard_html_headerがDTML Documentだった場合、title_or_idの取得はstandard_html_headerオブジェクト自身から行われる事になります。その結果、title_or_idの値取得先はindex_htmlオブジェクトであって欲しいのに、standard_html_headerオブジェクトを参照してしまい、 standard_html_header という文字列が出力されてしまいます。
このように、 DTML Methodオブジェクトは主体にはなりません 。このため、DTML Methodのコードで値の参照を行うと、主体となるオブジェクトに問い合わせて値を取得することになります。もし、DTML Methodオブジェクトを直接URLで指定して表示した場合、主体となるオブジェクトを探して親フォルダに問い合わせが行われて、親フォルダのtitleなどが取得される事になります。
まとめると、 他のオブジェクトから呼び出される場合は、DTML Methodを使うようにする ということになります。

