|
amritaはHTMLと同様、XMLに対しても使用することができます。
XHTMLのテンプレートを用意すれば、XHTML文書を作成します
amrita には HTMLのDTD(タグの構造)に依存したコードはわずかしかありません。 また、それらをOFFにすることが容易にできます。 ですから、XHTML以外の一般のXML文書をテンプレートとして使用することができます。
REXMLはRubyのための自然なAPIを提供しています。 そして、REXMLで読みこんだXML文書をモデルデータとして使用することが容易にできます。
docs/Tour2 を参照してください。
コード:
require "amrita/template" include Amrita tmpl_text = <<-END <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <head> <title>xhtml sample</title> </head> <body> <h1 id=title>title</h1> <p id=body>body text</p> <hr /> </body> </html> END
data = { :title => "SAMPLE1", :body => "members of this HASH will be inserted here and title" } tmpl = TemplateText.new tmpl_text tmpl.prettyprint = true tmpl.expand(STDOUT, data)
出力:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <head> <title>xhtml sample</title> </head> <body> <h1>SAMPLE1</h1> <p>members of this HASH will be inserted here and title</p> <hr /> </body> </html>
基本的に、amrita は XHTMLテンプレートからはXHTML文書、HTML4.0テンプレートからHTML4.0文書を作成します。 よって、プログラマーは特定の標準やブラウザ、デバイスに対する適合性をいちいち気にする必要がありません。 それは、デザイナー(テンプレートを書く人)の仕事になります。
フラグを設定することだけです。 これが true に設定されていると、 <hr> のような単独のタグは <hr /> のようにXMLの形式で出力されます。
コード:
data = { :table1=>[ { :name=>"Ruby In A Nutshell", :author=>"Yukihiro Matsumoto, David L. Reynolds", :isbn=>"0596002149" } { :name=>"Programming Ruby", :author=>"David Thomas, Andrew Hunt", :isbn=>"0201710897" }, { :name=>"The Ruby Way", :author=>"Hal Fulton", :isbn=>"0672320835" }, ] } <booklist> <book id="table1"> <title id="name" /> <author id="author" /> <isbn id="isbn" /> </book> </booklist> END
puts "------------XML output ----------------------"
出力:
<booklist> <book> <title>Ruby In A Nutshell</title> <author>Yukihiro Matsumoto, David L. Reynolds</author> <isbn>0596002149</isbn> </book><book> <title>Programming Ruby</title> <author>David Thomas, Andrew Hunt</author> ..........
puts "------------XML output ----------------------"
amritaは必要があるまでテンプレートをロードしません。 最初に expand href="../../classes/REXML.html">REXMLベースのパーサーを使用します。
amritaでは、ひとつのモデルデータを複数のテンプレートに適用することもできます。 従って、一種類のコードでXMLとHTMLを両方出力することもできます。 詳しくは
XML文書(データ) + HTMLテンプレート ==> HTML文書
つまり、一種のスタイルシートとしてamritaを利用する方法です。
code:
require "amrita/template" include Amrita doc = REXML::Document.new <<END <booklist> <book isbn="0596002149"> <title>Ruby In A Nutshell</title> <author>Yukihiro Matsumoto</author> <author>David L. Reynolds</author> </book> <book isbn="0201710897"> <title>Programming Ruby</title> <author>David Thomas</author> <author>Andrew Hunt</author> </book> <book isbn="0672320835"> <title>The Ruby Way</title> <author>Hal Fulton</author> </book> </booklist> END
table = doc.elements.to_a("booklist/book").collect do |book| { :title=>book.elements['title'], :authors=>book.elements.to_a('author').collect do |a| { :name=>a } end, #:isbn=>book.attributes['isbn'] :isbn=>e(:a, :href=>"http://www.amazon.com/exec/obidos/ASIN/#{book.attributes['isbn']}") { book.attributes['isbn'] } } end data = { :table1=>table }
html_tmpl = TemplateText.new <<END <table border="1"> <tr><th>title</th><th>author</th><th>ISBN</th></tr> <tr id=table1> <td id="title"> <td><span id="authors"><span id="name"></span><br></span> <td id="isbn"> </tr> </table> END html_tmpl.prettyprint = true html_tmpl.set_hint(HtmlCompiler::AnyData.new) html_tmpl.expand(STDOUT, data)
output:
<table border="1"> <tr> <th>title</th> <th>author</th> <th>ISBN</th> </tr> <tr> <td>Ruby In A Nutshell</td> <td>Yukihiro Matsumoto<br>David L. Reynolds <br> </td> <td><a href="http://www.amazon.com/exec/obidos/ASIN/0596002149">0596002149</a></td> </tr> <tr> <td>Programming Ruby</td> <td>David Thomas<br>Andrew Hunt <br> </td> <td><a href="http://www.amazon.com/exec/obidos/ASIN/0201710897">0201710897</a></td> </tr> <tr> <td>The Ruby Way</td> <td>Hal Fulton<br> </td> <td><a href="http://www.amazon.com/exec/obidos/ASIN/0672320835">0672320835</a></td> </tr> </table>
table = doc.elements.to_a("booklist/book").collect do |book| { :xxx=>..... } end
このコードは、<book>要素から含むHashの配列を生成します。 <book>要素はREXML::Elementクラスのインスタンスです。 ですから、REXMLのAPIによって、下位ノードや属性値を取り出すことができます。
:title=>book.elements['title'],
book.elements['title']は、<book> 要素が持つ最初の <title> 要素です。
:authors=>book.elements.to_a('author').collect do |a| { :name=>a } end,
一冊の本にはタイトルは一つしかありませんが、著者は複数いる場合があります。 従って、著者(author)は to_aによってArrayとして処理します。 Ruby の標準メソッドである、collectを使用してHashの配列を作成しています。
:isbn=>e(:a, :href=>"http://www.amazon.com/exec/obidos/ASIN/#{book.attributes['isbn']}") { book.attributes['isbn'] }
この例では、アマゾンへの直接リンクを貼ろうとしています。 e(...) { ... } は次のようなタグを生成します。
<a href="http://www.amazon.com/exec/obidos/ASIN/0596002149">0596002149</a>
このアイディア(amritaベースのXMLスタイルシート)をさらに発展させた例が という機能としてまとめられています。 詳細は docs/Tour2 を参照してください。
RubyのオブジェクトをXMLに対応させようとすると、 属性に対応するメンバーと下位要素に対応するメンバーがあると思います。
このサンプルは、ls -lのような情報をXMLとして提供する例です。
コード:
amrita can use an existing class for model data. To show this ability, this sample uses Ruby's system class File::Stat. require "amrita/template" include Amrita
class File class Stat include Amrita::ExpandByMember def entry(name) a(:name=>name, :type=>ftype) { self } end
def size_or_nil size if ftype == "file" end def mode_str ret = "-rwxrwxrwx" /(.*)(.)(.)(.)(.)(.)(.)(.)(.)(.)$/ =~ sprintf("%b",mode) $~[2..10].each_with_index do |b,n| ret[n+1] = "-" if b != "1" end ret[0] = "d" if $~[1] == "100000" ret end
def unix_inf a(:dev=>dev, :uid=>uid, :gid=>gid) { self } end end end tmpl = TemplateText.new <<END <file id="filelist"> <size id="size_or_nil" /> <mode id="mode_str" /> <times> <ctime id="mtime" /> <mtime id="mtime" /> <atime id="atime" /> </times> <unix_inf id="unix_inf"> <inode id="ino" /> </unix_inf> </file> END
dir = ARGV.shift || '*' filelist = Dir[dir].collect do |f| File::stat(f).entry(f) end
data = { :filelist=>filelist } tmpl.expand(STDOUT, data)
出力:
<file name="CVS" type="directory"> <mode>drwxr-xr-x</mode> <times> <ctime>Tue Sep 03 11:07:10 JST 2002</ctime> <mtime>Tue Sep 03 11:07:10 JST 2002</mtime> <atime>Thu Sep 05 07:30:39 JST 2002</atime> </times> <unix_inf uid="1000" gid="1000" dev="770"> <inode>652250</inode> </unix_inf> </file> <file name="precompile.rb" type="file"> <size>2596</size> <mode>-rw-r--r--</mode> <times> <ctime>Mon Aug 26 09:12:11 JST 2002</ctime> <mtime>Mon Aug 26 09:12:11 JST 2002</mtime> <atime>Thu Sep 05 09:26:48 JST 2002</atime> </times> <unix_inf uid="1000" gid="1000" dev="770"> <inode>310411</inode> </unix_inf> </file> <file name="amstest.ams" type="file"> .....
def entry(name) a(:name=>name, :type=>ftype) { self } end
このメソッドはAttrArrayオブジェクトを生成し、 一部の属性値を設定してから下位要素を自分自身で展開します。
def size_or_nil size if ftype == "file" end
もしファイルが通常ファイルでないと、 このメソッドはnilを返し、<size> 要素は削除されます。