Template::Semantic::Cookbook - Template::Semantic Recipes, tricks, hints
Use XPath power.
print Template::Semantic->process(\*DATA, { 'table tbody tr' => [ { '//td[1]' => '101', '//td[2]' => '102' }, { '//td[1]' => '201', '//td[2]' => '202' }, { '//td[1]' => '301', '//td[2]' => '302' }, { '//td[1]' => '401', '//td[2]' => '402' }, ], })->process({ '//table/tbody/tr[position() mod 2 = 0]/@class' => 'even', }); __DATA__ <table> <thead> <tr> <th>Foo</th> <th>Bar</th> </tr> </thead> <tbody> <tr class=""> <td>sample</td> <td>sample</td> </tr> </tbody> </table>
Output:
<table> <thead> <tr> <th>Foo</th> <th>Bar</th> </tr> </thead> <tbody> <tr class=""> <td>101</td> <td>102</td> </tr> <tr class="even"> <td>201</td> <td>202</td> </tr> <tr class=""> <td>301</td> <td>302</td> </tr> <tr class="even"> <td>401</td> <td>402</td> </tr> </tbody> </table>
If you don't like class="", do this.
class=""
print Template::Semantic->process(\*DATA, { ... )->process({ '//table//tr[position() mod 2 = 0]/@class' => 'even', '//table//tr[position() mod 2 = 1]/@class' => undef, });
If you want to set the value for JavaScript...
print $ts->process(\*DATA, { 'script[src="foo.js"]@src' => 'http://prod-server/foo.js', '//script[2]' => 'var = ' . JSON::to_json($var_to_js), }); __DATA__ <html> <script type="text/javascript" src="foo.js"></script> <script type="text/javascript"></script> ... </html>
The following example is NOT output as <div class="foo">foo</div> but instead as <div>foo</div> because LibXML cannot find class attribute in <div>.
<div class="foo">foo</div>
<div>foo</div>
class
<div>
print Template::Semantic->process(\'<div>foo</div>', { 'div@class' => 'foo', });
You can add the attribute with the on-demand.
print Template::Semantic->process(\'<div>foo</div>', { 'div' => sub { shift->setAttribute(class => 'foo'); \$_ }, });
But I think that you should prepare place holder.
print Template::Semantic->process(\'<div class="">foo</div>', { 'div@class' => 'foo', });
If template contains dummy items to check design, you may delete them first.
print Template::Semantic->process(\*DATA, { '.dummy' => undef, # remove dummys first })->process({ 'ul li' => [ { '.' => 'AAA' }, { '.' => 'BBB' }, { '.' => 'CCC' }, { '.' => 'DDD' }, { '.' => 'EEE' }, ], }); __DATA__ <ul> <li>sample</li> <li class="dummy">sample</li> <li class="dummy">sample</li> <li class="dummy">sample</li> </ul>
<ul> <li>AAA</li> <li>BBB</li> <li>CCC</li> <li>DDD</li> <li>EEE</li> </ul>
Idea 1 - Original data-id attribute like Template::TAL:
data-id
print Template::Semantic->process(\*DATA, { '//*[@data-id="foo"]' => 'foo', '//*[@data-id="bar"]' => 'bar', })->process({ '//@data-id' => undef, }); __DATA__ <div> <span data-id="foo">xxx</span> <span data-id="bar">xxx</span> </div>
Idea 2 - Original x-foobar class:
x-foobar
print Template::Semantic->process(\*DATA, { '.x-foo' => 'foo', '.x-bar' => 'bar', })->process({ '//span[contains(@class,"x-")]/@class' => sub { join " ", grep { !/^x-/ } split /\s+/; }, }); __DATA__ <div> <span class="x-foo">xxx</span> <span class="x-bar">xxx</span> </div>
Output format config in template:
print Template::Semantic->process(\*DATA, { '.date' => sub { my $date = localtime; # or DateTime->now $date->strftime( shift->getAttribute('data-format') ); }, })->process({ '//@data-format' => undef, }); __DATA__ <div class="entry"> <div class="date" data-format="%Y/%m/%d">2010/99/99</div> </div>
<div class="entry"> <div class="date">2010/02/08</div> </div>
You should use the module like Template-Toolkit ;) But if you want to use this module anyway,
my $res = $ts->process(\*DATA, { 'name' => 'Foo & Co.', }); my $subj = $res->dom->documentElement->findvalue('//*[@class="subject"]'); my $body = $res->dom->documentElement->findvalue('//*[@class="body"]'); __DATA__ <html> Subject: <b class="subject">Dear <name>name</name></b> <hr /> Body: <pre class="body">Dear <name>name</name>, bla bla bla bla </pre> </html>
It is easy to substitute another process().
process()
my $ts = Template::Semantic->new; print $ts->process('wrapper.html', { '#container' => $ts->process('include.html'), });
It is possible though is tricky.
my $ts = Template::Semantic->new; print $ts->process('foo.html', { '/div' => sub { my $node = shift; # Get wrapper filename from attribute ... my $wrapper = $node->getAttribute('wrapper'); # Process wrapper.html ... # embed this innerHTML to wrapper.html's <div id="content"> my $res = $ts->process($wrapper, { '#content' => \$_ }); # Insert result(as XML::LibXML::Element) after me. $node->addSibling($res->dom->documentElement); # And delete me. return undef; } })->process({ 'h1' => 'Hello world!', });
foo.html
<div wrapper="wrapper.html"> <h1>foo</h1> <p>bla bla bla</p> </div>
wrapper.html
<html> <body> <div id="content"> </div> </body> </html>
<html> <body> <div id="content"> <h1>Hello world!</h1> <p>bla bla bla</p> </div> </body> </html>
Blog it ;)
Naoki Tomita <tomita@cpan.org>
To install Template::Semantic, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Template::Semantic
CPAN shell
perl -MCPAN -e shell install Template::Semantic
For more information on module installation, please visit the detailed CPAN module installation guide.