Cindy
view release on metacpan or search on metacpan
lib/Cindy.pm view on Meta::CPAN
our @EXPORT= qw(get_html_doc get_xml_doc
parse_html_string parse_xml_string
parse_cis parse_cis_string
inject dump_xpath_profile);
use XML::LibXML;
use Cindy::Sheet;
use Cindy::Log;
sub get_html_doc($)
{
my ($file) = @_;
my $parser = XML::LibXML->new();
return $parser->parse_html_file($file);
}
sub get_xml_doc($)
{
my ($file) = @_;
my $parser = XML::LibXML->new();
return $parser->parse_file($file);
}
sub omit_nodes {
my ($doc, $tag) = @_;
my $found = $doc->find( "///$tag" );
foreach my $node ($found->get_nodelist()) {
my $parent = $node->parentNode;
foreach my $child ($node->childNodes()) {
$parent->insertBefore($child->cloneNode(1), $node);
}
$parent->removeChild($node);
}
}
sub parse_html_string($;$)
{
my ($string, $ropt) = @_;
$ropt ||= {};
my $html_parse_noimplied = $ropt->{html_parse_noimplied}
|| $ropt->{no_implied};
my $dont_omit = !$html_parse_noimplied
|| ($string =~ /<html|<body/i);
my $parser = XML::LibXML->new();
my $doc = $parser->parse_html_string($string, $ropt);
if (!$dont_omit) {
# Until HTML_PARSE_NOIMPLIED is implemented by
# libxml2 (and passed by XML::LibXML) we need
# to remove html/body tags that have been added to
# fragments.
omit_nodes($doc, 'html');
omit_nodes($doc, 'body');
}
return $doc;
}
sub parse_xml_string($)
{
my $parser = XML::LibXML->new();
return $parser->parse_string($_[0]);
}
sub parse_cis($)
{
return Cindy::Sheet::parse_cis($_[0]);
}
sub parse_cis_string($)
{
return Cindy::Sheet::parse_cis_string($_[0]);
}
#
# Get a copied doc. root for modification.
#
sub get_root_copy($)
{
my ($doc) = @_;
my $root = $doc->documentElement();
my $rtn = $root->cloneNode( 1 );
return $rtn;
}
sub dump_xpath_profile()
{
Cindy::Injection::dump_profile();
}
sub inject($$$)
{
my ($data, $doc, $descriptions) = @_;
my $docroot = get_root_copy($doc);
# my $dataroot = get_root_copy($data);
my $dataroot = $data->getDocumentElement();
# Create a root description with action none
# to hold the description list
my $descroot = Cindy::Injection->new(
'.', 'none', '.', 'xpath',
sublist => $descriptions);
# Connect the copied docroot with the output document.
# This has to be done before the tree is matched.
my $out = XML::LibXML::Document->new($doc->getVersion, $doc->getEncoding);
# Copy doctypes
# This worked for 2.0001/2.8.0 (wheezy),
# but does look somewhat clumsy.
if ($doc->externalSubset) {
my $ext = $doc->externalSubset;
$out->createExternalSubset($ext->getName(),
lib/Cindy.pm view on Meta::CPAN
<source> content <target> ;
true() omit-tag <target> ;
If no source node matched, the target node will be left unchanged.
=head3 copy
The source node with all its content replaces the target node
and all its content. This means that the target tag including any
content is replaced by the the source tag and its content.
If no source node matched, the target node will be left unchanged.
Be aware that this requires the source tag to be valid in the target
document.
=head3 omit-tag
The source node is used as a condition. If it exists and if its text
content evaluates to true the target node is replaced by its children.
This means that if the source tag exists and its content is not '' or
0 the target tag is removed while its content remains.
=head3 comment
The source nodes content is moved into a comment node. This comment node
is appended to the children of the target node. This can be useful for
debugging and enables injection of SSI directives.
=head3 attribute
The syntax has an additional field atname
<source> attribute <target> <atname> ;
that holds the name of the attribute. If the source node exists, its
content replaces or sets the value of the atname attribute of the
target node. If the source node does not exist the attribute atname
is removed from the target node.
=head3 condition
The source node is used as a condition. If it exists and if its text
content evaluates to true nothing is done. Otherwise the target node
and its children are removed. This means that the target tag is removed
if the source tage does not exist or contains '', 0 or 0.0 while it is
left untouched otherwise.
=head3 repeat
The repeat action is the CJS equivalent of a template engines loop. For
each match of the source path the source node and the target node are
used as root nodes for a sequence of actions. The syntax is
<source> repeat <target> [condition] {
<actions>
} ;
The optional condition is an xpath expression that is run in the context
of the root node of a temporary document fragment. The fragment has
two children, DOC and DATA which hold a subtree from a repeat doc respective data
match. Only those combinations where the condition evaluates to true are
used, all others are discarded.
Note that the repeat condition is an EXPERIMENTAL feature, it may well
change.
=head2 XPATH FUNCTIONS
A small number of additional XPath functions have been implemented.
=head3 current()
This returns the context node. It behaves like the identically
named XSLT function.
=head1 ERROR HANDLING
As a default Cindy dies on errors. Currently there are no warnings.
Cindy detects log4perl and uses it for trace logging
with levels DEBUG and INFO. If Cindy is used from Cindy-Apache2 the
apache log is used instead.
=head1 AUTHOR
Joachim Zobel <jz-2008@heute-morgen.de>
=head1 SEE ALSO
See Cindy/CJSGrammar.rdc for the RecDescent grammar for content injection sheets.
If you prefer a classic push template engine, that uses an API to fill the template
from within the application see L<http://search.cpan.org/~tomita/Template-Semantic>.
This also uses xpath or css selectors to move data into unmodified templates.
( run in 0.741 second using v1.01-cache-2.11-cpan-364913b4093 )