NAME
    Template::Semantic - Use pure XHTML/XML as a template

SYNOPSIS
      use Template::Semantic;
  
      print Template::Semantic->process('template.html', {
          'title, h1' => 'Naoki Tomita',
          'ul.urls li' => [
              {
                  'a' => 'Homepage >',
                  'a@href' => 'http://e8y.net/',
                  'a@target' => undef,
              },
              {
                  'a' => 'Twitter >',
                  'a@href' => 'http://twitter.com/tomita/',
                  'a@target' => '_blank',
              },
          ],
      });

    template:

      <html>
          <head><title>person name</title></head>
          <body>
              <h1>person name</h1>
              <ul class="urls">
                  <li><a href="#" target="">his page</a></li>
              </ul>
          </body>
      </html>

    output:

      <html>
          <head><title>Naoki Tomita</title></head>
          <body>
              <h1>Naoki Tomita</h1>
              <ul class="urls">
                  <li><a href="http://e8y.net/">Homepage &gt;</a></li>
                  <li><a href="http://twitter.com/tomita/" targer="_blank">Twitter &gt;</a></li>
              </ul>
          </body>
      </html>

DESCRIPTION
    Template::Semantic is a template engine for XHTML/XML that doesn't use
    any template syntax. This module takes pure XHTML/XML as a template, and
    uses XPath or CSS selector to assign value.

    This is beta release. Your feedback is welcome.

    See Template::Semantic::Cookbook for the practical examples.

METHODS
    $ts = Template::Semantic->new( %options )
        Constructs a new "Template::Semantic" object.

          my $ts = Template::Semantic->new;
          my $out = $ts->process(...);

        Template::Semantic uses XML::LibXML parser as follows by default.

          my $parser = XML::LibXML->new;
          $parser->no_newwork(1); # faster
          $parser->recover(2);    # = recover_silently(1) = no warnings

        If you may not change this, call "process()" directly, skip "new()".

          my $out = Template::Semantic->process(...);

        Set %options if you want to change parser options:

        *   "parser"

            Set if you want to replace XML parser. It should be XML::LibXML
            based.

              my $ts = Template::Semantic->new(
                  parser => $your_libxml_parser,
              );

        *   (others)

            All other parameters except "parser" are passed to XML parser
            like "$parser->$key($value)". See XML::LibXML::Parser for
            details.

              my $ts = Template::Semantic->new(
                  recover => 1,
                  expand_xinclude => 1,
              );

    $out = $ts->process($filename, \%vars)
    $out = $ts->process(\$text, \%vars)
    $out = $ts->process(FH, \%vars)
        Process a template and returns Template::Semantic::Document object.

        The 1st parameter is the input template that can take these types:

          # filename
          my $out = Tempalte::Semantic->('template.html', $vars);
  
          # text reference
          my $out = Tempalte::Semantic->(\'<html><body>foo</body></html>', $vars);
  
          # file handle
          my $out = Tempalte::Semantic->($fh, $vars);
          my $out = Tempalte::Semantic->(\*DATA, $vars);

        The 2nd parameter is a value set to bind the template. This should
        be hash-ref like { 'selector' => $value, 'selector' => $value, ...
        }. See below "SELECTOR" and "VALUE TYPE" section.

    $ts->define_filter($filter_name, \&code)
    $ts->call_filter($filter_name)
        See "Filter" section.

SELECTOR
    Use XPath expression or CSS selector as a selector.

      print Tempalte::Semantic->process($template, {
      
          # XPath sample that indicate tag:
          '/html/body/h2[2]' => ...,
          '//title | //h1'   => ...,
          '//img[@id="foo"]' => ...,
          'id("foo")'        => ...,
      
          # XPath sample that indicate attribute:
          '//a[@id="foo"]/@href'              => ...,
          '//meta[@name="keywords"]/@content' => ...,
      
          # CSS selector sample that indicate tag:
          'title'         => ...,
          '.foo span.bar' => ...,
          '#foo'          => ...,
      
          # CSS selector sample that indicate attribute:
          'img#foo@src'     => ...,
          'span.bar a@href' => ...,
  
      });

    Note 1: CSS selector is converted to XPath internally. You can use
    '@attr' expression to indicate attribute in this module unlike CSS
    format.

    Note 2: You can use 'id()' function in XHTML (with "html xmlns="..."")
    without using XML::LibXML::XPathContext. This module sets "xmlns="""
    namespace declarations automatically if template like a XHTML.

VALUE TYPE
  Basics
    *   selector => $text

        *Scalar:* Replace the inner content with this as Text.

          $ts->process($template, {
              'h1' => 'foo & bar',   # <h1></h1> =>
                                     # <h1>foo &amp; bar</h1>
       
              '.foo@href' => '/foo', # <a href="#" class="foo">bar</a> =>
                                     # <a href="/foo" class="foo">bar</a>
          });

    *   selector => \$html

        *Scalar-ref:* Replace the inner content with this as flagment
        XML/HTML.

          $ts->process($template, {
              'h1' => \'<a href="#">foo</a>bar', # <h1></h1> =>
                                                 # <h1><a href="#">foo</a>bar</h1>
          });

    *   selector => undef

        *undef:* Delete the element/attirbute that the selector indicates.

          $ts->process($template, {
              'h1'            => undef, # <div><h1></h1>foo</div> =>
                                        # <div>foo</div>
      
              'div.foo@class' => undef, # <div class="foo">foo</div> =>
                                        # <div>foo</div>
          });

    *   selector => \&foo

        *Code-ref:* Callback subroutine. Subroutine can user $_ as inner
        HTML or first argument as XML::LibXML::Node object.

          $ts->process($template, {
              'h1' => sub { uc },  # <h1>foo</h1> => <h1>FOO</h1>
              'h1' => sub {
                  my $node = shift;
                  $node->nodeName; # <h1>foo</h1> => <h1>h1</h1>
              },
          });

    *   selector => XML::LibXML::Node

        Replace the inner content by the node.

          $ts->process($template, {
              'h1' => do { XML::LibXML::Text->new('foo') },
          });

    *   selector => Template::Semantic::Document

        Replace the inner content by another "process()"-ed result.

          $ts->process('wrapper.html', {
              'div#content' => $ts->process('inner.html', ...),
          });

    *   selector => { 'selector' => $value, ... }

        *Hash-ref:* Sub query of the part.

          $ts->process($template, {
              'div.foo' => {
                  'a' => undef, # All <a> tag *in <div class="foo">* disappears
              },
   
              'div.foo a' => undef, # same as above
          });

  Loop
    *   selector => [ \%row, \%row, ... ]

        *Array-ref of Hash-refs:* Loop the part as template. Each item of
        the array-ref should be hash-ref.

          $ts->process(\*DATA, {
              'table.list tr' => [
                  { 'th' => 'aaa', 'td' => '001' },
                  { 'th' => 'bbb', 'td' => '002' },
                  { 'th' => 'ccc', 'td' => '003' },
              ],
          });
  
          __DATA__
          <table class="list">
              <tr>
                  <td></td>
                  <td></td>
              </tr>
          </table>

        Output:

          <table class="list">
              <tr>
                  <th>aaa</th>
                  <td>001</td>
              </tr>
              <tr>
                  <th>bbb</th>
                  <td>002</td>
              </tr>
              <tr>
                  <th>ccc</th>
                  <td>003</td>
              </tr>
          </table>

  Filter
    *   selector => [ $value, filter, filter, ... ]

        *Array-ref of Scalars:* Value and filters. Filter can take

        A) Callback subroutine

        B) Defined filter name

        C) Object like Text::Pipe ("it->can('filter')")

          $ts->process($template, {
              'h1' => [ 'foo', sub { uc }, sub { "$_!" } ], # => <h1>FOO!</h1>
              'h2' => [ ' foo ', 'trim', sub { "$_!" } ],   # => <h2>FOO!</h2>
              'h3' => [ 'foo', PIPE('UppercaseFirst') ],    # => <h3>Foo</h3>
          });

        Defined basic filters
            Some basic filters included. See Template::Semantic::Filter.

        $ts->define_filter($filter_name, \&code)
            You can define the your filter name using "define_filter()".

              use Text::Markdown qw/markdown/;
              $ts->define_filter(markdown => sub { \ markdown($_) })
              $ts->process($template, {
                  'div.content' => [ $text, 'markdown' ],
              });

        $code = $ts->call_filter($filter_name)
            Accessor to defined filter.

              $ts->process($template, {
                  'div.entry'      => ...,
                  'div.entry-more' => ...,
              })->process({
                  'div.entry, div.entry-more' => $ts->call_filter('markdown'),
              });

SEE ALSO
    Template::Semantic::Cookbook

    XML::LibXML, HTML::Selector::XPath

    I got a lot of ideas from Template, Template::Refine, Web::Scraper.
    thanks!

AUTHOR
    Naoki Tomita <tomita@cpan.org>

    Feedback, patches, POD English check are always welcome!

LICENSE
    This library is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself.