The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Template::Semantic::Cookbook - Template::Semantic Recipes, tricks, hints

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

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

For JavaScript vars

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>

Create attribute

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

  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',
  });

Dummy items

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>

Output:

  <ul>
      <li>AAA</li>
      <li>BBB</li>
      <li>CCC</li>
      <li>DDD</li>
      <li>EEE</li>
  </ul>

Indicator only for Temlate::Semantic

Idea 1 - Original data-id attribute like Template::TAL:

  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:

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

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>

Output:

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

Email template?

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>

Include

It is easy to substitute another process().

  my $ts = Template::Semantic->new;
  print $ts->process('wrapper.html', {
      '#container' => $ts->process('include.html'),
  });

Wrapper/Template inheritance

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>

Output:

  <html>
      <body>
          <div id="content">
      <h1>Hello world!</h1>
      <p>bla bla bla</p>
          </div>
      </body>
  </html>

Do you have another good usage?

Blog it ;)

AUTHOR

Naoki Tomita <tomita@cpan.org>