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

NAME

HTML::Inject - inject content from one HTML file into another

SYNOPSIS

 use HTML::Inject;
 
 my $template = HTML::Inject::->new(dom => <<'TARGET');
 <!doctype html>
 <html>
    <head></head>
    <body>
       <div id="content"></div>
       <p class="copyright">&copy; 2012 Acme Inc</p>
    </body>
 </html>
 TARGET
 
 my $result = $template->inject(<<'SOURCE');
 <!doctype html>
 <html>
    <head>
       <title>Hello World</title>
    </head>
    <body>
       <div id="content">A greeting to the planet!</div>
    </body>
 </html>
 SOURCE
 
 print $result->toString;
 # <!doctype html>
 # <html>
 #    <head>
 #       <title>Hello World</title>
 #    </head>
 #    <body>
 #       <div id="content">A greeting to the planet!</div>
 #       <p class="copyright">&copy; 2012 Acme Inc</p>
 #    </body>
 # </html>

DESCRIPTION

HTML::Inject is a "template system lite". It allows you to inject content from one HTML file (the "source") into another HTML file (the "target") that has placeholders for that content.

Constructor

new(%attr)

Moose-style constructor, accepting a hash of attributes. (Actually this package uses Moo.)

Attributes

target

The target HTML to inject. May be provided as an XML::LibXML::Document object, a file handle, a URL, a filename or a plain string of HTML. (To disambiguate between a string of HTML, and a filename/URL which is also a string, strings of HTML must contain at least one line break character!!) Whatever is provided, it will be coerced into an XML::LibXML::Document.

head_element_test

A coderef which takes an XML::LibXML::Element object and returns a boolean. The default is probably fairly sane, matching all <title>, <link>, <meta> and <style> elements.

See "Injection Technique" for an explanation of the head element test.

body_element_test

A coderef which takes an XML::LibXML::Element object and returns a boolean. The default is probably fairly sane, matching all <script> and <map> elements.

See "Injection Technique" for an explanation of the body element test.

missing_nodes

An arrayref of XML::LibXML::Node objects. You should probably not set this attribute in the constructor, or indeed at all. It's intended as a place for HTML::Inject to pass back problem nodes to the caller.

Methods

inject($source)

Injects content from the source into the target returning an XML::LibXML::Document as the result. The result is generated by deep cloning the target, thus the same target can be reused again and again with different source data.

Like the target passed to the constructor, the source data can be provided as an XML::LibXML::Document object, a file handle, a URL, a filename or a plain string of HTML. It may also be an arrayref of any of the above.

See "Injection Technique" for more details.

inject_and_new($source)

As per inject, but returns the result as a new HTML::Inject target. That is, this:

 my $template2 = $template->inject_and_new($content);

is equivlent to:

 my $template2 = HTML::Inject::->new(
    $template->inject($content),
 );

This is vaguely useful for some chanined operations.

Injection Technique

Before beginning the injection, the missing_nodes list is cleared.

As a first step, HTML::Inject finds a list of potentially injectable nodes in the source document. Potentially injectable things are any nodes which are direct children of the HTML <head> and <body> elements.

It then loops through the potentially injectable nodes.

For elements which have an @id attribute, the injection technique is to find the element with the corresponding @id in the target document, and then clone the source element's contents and attributes onto the target element. If the target element already has contents, these will not be removed, and the new content is added after the existing content.

Nodes without an @id attribute are handled differently: they are added to the end of the target document's HTML <head> or <body> element, but only if the element passes the head_element_test or body_element_test. (Elements which pass both tests will be added to the <head>.) This allows certain elements from the source document like <meta>, <title> and <script> to be injected to the target document without having to worry too much about exactly where they're injected. They won't be injected in any especially predictable order.

Any potentially injectable nodes which have not been injected will be pushed onto the missing_nodes list. You may wish to loop through this list yourself, adding them to the result document using some sort of logic of your choice.

HTML Parsing

HTML parsing is via HTML::HTML5::Parser which supports some nicely idiomatic HTML. The example in the "SYNOPSIS" could have used:

 my $result = $template->inject(<<'SOURCE');
 <title>Hello World</title>
 <div id="content">A greeting to the planet!</div>
 SOURCE

That is, for the source content, you only really need to include the actual elements that you wish to inject. You can ignore the "skeletal parts" of the HTML.

HTML Output

The result of inject is an XML::LibXML::Document element. This can be stringified using its toString method. See XML::LibXML::Node for details.

If serving the output as text/html, then you may be better off stringifying it using HTML::HTML5::Writer which makes special effort to stringify documents in a way browsers can actually cope with.

If you want your HTML nicely indented, try XML::LibXML::PrettyPrint. (Indenting is nice when you're debugging, but you may wish to switch it off for deployment, as it imposes a performance penalty.)

BUGS

Please report any bugs to http://rt.cpan.org/Dist/Display.html?Queue=HTML-Inject.

SEE ALSO

Cindy, Apache2::Layout, Template::Semantic.

AUTHOR

Toby Inkster <tobyink@cpan.org>.

COPYRIGHT AND LICENCE

This software is copyright (c) 2012 by Toby Inkster.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

DISCLAIMER OF WARRANTIES

THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.