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: person name

person name

output: Naoki Tomita

Naoki Tomita

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->(\'foo', $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', #

=> #

foo & bar

'.foo@href' => '/foo', # bar => # bar }); * selector => \$html *Scalar-ref:* Replace the inner content with this as flagment XML/HTML. $ts->process($template, { 'h1' => \'foobar', #

=> #

foobar

}); * selector => undef *undef:* Delete the element/attirbute that the selector indicates. $ts->process($template, { 'h1' => undef, #

foo
=> #
foo
'div.foo@class' => undef, #
foo
=> #
foo
}); * 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 }, #

foo

=>

FOO

'h1' => sub { my $node = shift; $node->nodeName; #

foo

=>

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 tag *in
* 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__
Output:
aaa 001
bbb 002
ccc 003
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 { "$_!" } ], # =>

FOO!

'h2' => [ ' foo ', 'trim', sub { "$_!" } ], # =>

FOO!

'h3' => [ 'foo', PIPE('UppercaseFirst') ], # =>

Foo

}); 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 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.