NAME

Template::Semantic::Cookbook - Template::Semantic Recipes

RECIPES

Zebra tables

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//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.

print Template::Semantic->process(\*DATA, {
    ...
)->process({
    '//table//tr[position() mod 2 = 0]/@class' => 'even',
    '//table//tr[position() mod 2 = 1]/@class' => undef,
});

Add attribute

The following example is output with NOT <div class="foo">foo</div> like <div>foo</div> because LibXML cannot find class attribute in <div>.

print Template::Semantic->process(\'<div>foo</div>', {
    'div@class' => 'foo',
});

Solution:

print Template::Semantic->process(\'<div>foo</div>', {
    'div' => sub { shift->setAttribute(class => 'foo'); \$_ },
});

Or:

print Template::Semantic->process(\'<div class="">foo</div>', {
    'div@class' => 'foo',
});

Remove dummy items

Template (includes dummy items to check design):

<ul>
    <li>sample</li>
    <li class="dummy">sample</li>
    <li class="dummy">sample</li>
    <li class="dummy">sample</li>
</ul>

Code:

print Template::Semantic->process($template, {
    '.dummy' => undef, # remove dummys first
})->process({
    'ul li' => [
        { '/li' => 'AAA' },
        { '/li' => 'BBB' },
        { '/li' => 'CCC' },
        { '/li' => 'DDD' },
    ],
});

Remove indicator used only for Temlate::Semantic

Use your own attribute:

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>

Or:

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>

Some custom filter ideas...

Set output format 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>

Output:

<div class="entry">
    <div class="date">2010/02/08</div>
</div>

Another sample:

use Text::Markdown;

my $ts = Template::Semantic->new;
$ts->define_filter(markdown => sub { \ Text::Markdown::markdown($_) });

print $ts->process(\*DATA, {
    'div.content' => sub {
        $ts->call_filter( shift->getAttribute('data-format') );
    },
})->process({
    '//@data-format' => undef,
});

__DATA__
<div class="container">
    <div class="content" data-format="markdown">
        *bla* bla bla
    </div>
    <div class="content" data-format="html_line_break">
        bla bla bla
    </div>
</div>

Do you have another good usage?

Blog it ;)

AUTHOR

Naoki Tomita <tomita@cpan.org>