XML::XSS - XML stylesheet system
version 0.3.5
use XML::XSS; my $xss = XML::XSS->new; $xss->set( pod => { pre => "=pod\n", post => "=cut\n", } ); $xss->set( section => { pre => \&pre_section } ); sub pre_section { my ( $self, $node, $args ) = @_; return "=head1 " . $node->findvalue( '@title' ) . "\n\n"; } print $xss->render( <<'END_XML' ); <pod> <section title="NAME">XML::XSS - a XML stylesheet system</section> ... </pod> END_XML
Caution: this is alpha-quality software. Here be enough dragons to send Beowulf packing. Caveat maximus emptor.
XML::XSS is a XML stylesheet system loosely similar to CSS and XSLT. A XML::XSS object is made up of rendering rules that dictate how the different nodes of an XML document are to be rendered, and can be applied against one or many XML documents.
XML::XSS
XML::XSS is a rewrite of XML::XPathScript, which was initially part of the AxKit framework.
XML::XSS uses XML::LibXML under the hood as its XML DOM API. Documents can be passed as strings, in which case the creation of the XML::LibXML object will be done behind the curtain
$xss->render( '<foo>yadah</foo>' );
or the XML::LibXML object can be passed directly
my $doc = XML::LibXML->load_xml( location => 'foo.xml' ); $xss->render( $doc );
XML::XSS has 5 different kinds of rules that reflect the different kinds of nodes that a XML document can have (as per XML::LibXML): XML::XSS::Document, XML::XSS::Text, XML::XSS::Comment, XML::XSS::ProcessingInstruction and XML::XSS::Element. Whereas there are can many XML::LibXML::Element rules, there is only one instance of each of the first 4 rules per stylesheet. In addition of the regular XML::LibXML::Element rules, a special catch-all XML::LibXML::Element also exists that will be applied to any document element not explicitly matched by one of the element rules.
XML::LibXML::Element
Each rule has a set of style attributes that control how the matching document node is transformed. The different types of rule (XML::XSS::Document, XML::XSS::Element, XML::XSS::Text, XML::XSS::Comment and XML::XSS::ProcessingInstruction) have each a different set of style attributes, which are described in their relative manpages.
Unless specified otherwise, a style attribute can be assigned a scalar value or a reference to a sub. In the second case, the sub will be evaluated in the context of the processed node and its return value will be used as the style attribute value.
Upon execution, the sub references will be passed three parameters: the invoking rule, the XML::LibXML node it is rendering and the arguments ref given to render().
XML::LibXML
render()
$css->set( 'foo' => { pre => '[[[', post => sub { my ( $self, $node, $args ) = @_; return $node->findvalue( '@bar' ); } } );
Rules attributes changed while rendering only apply to the current element.
$xss->set( 'section' => { process => sub { my ( $self, $node ) = @_; $self->stash->{section_nbr}++; if ( $self->stash->{section_nbr} == 5 ) { # only applies to the one section $self->set_pre( '>>> this is the fifth section <<<' ); } return 1; } } );
If you want to change the global rule, you have to access the rule from the stylesheet, like so
$xss->set( 'section' => { process => sub { my ( $self, $node ) = @_; $self->stash->{section_nbr}++; if ( $self->stash->{section_nbr} == 6 ) { $self->stylesheet->element('section')->set_pre( '>>> this is after the fifth section <<<' ); } return 1; } } );
The document rule. Note that this matches against the XML::LibXML::Document node, not the root element node of the document.
XML::LibXML::Document
Attribute getter.
The text rule.
Shortcut for
$xss->text->set( ... );
$xss->text->clear;
The comment rule.
$xss->comment->set( ... )
The collection of user-defined element rules.
Returns the XML::XSS::Element node associated to the tag $name. If the element didn't already exist, it is automatically created.
$name
my $elt = $xss->element( 'foo' ); # element for <foo> $elt->set( pre => '[foo]' );
The catch-all element rule, which is applied to all the element nodes that aren't explicitly matched.
# change all tags to <unknown> except for <foo> $xss->set( 'foo' => { showtag => 1 } ); $xss->set( '*' => { rename => 'unknown' } );
The attribute getter.
The stylesheet has a stash (an hashref) that is accessible to all the rules during the rendering of a document, and can be used to pass information back and forth.
$xss->set( section => { intro => \§ion_title, } ); # turns <section title="blah"> ... # into 1. blah sub section_title { my ( $self, $node, $args ) = @_; my $section_nbr = $self->stash->{section_nbr}++; return $section_nbr . ". " . $node->findvalue( '@title' ); }
By default, the stash is cleared when rendering a document. To change this behavior, see "use_clean_stash" in XML::XSS::Document.
Clear the stash.
The concatenation operator is overloaded to behave as an alias for get().
get()
my $chapter = $xss.'chapter'; # just like $xss->get('chapter') $chapter->set_pre( '<div class="chapter">' ); $chapter->set_post( '</div>' );
Gets really powerful when used in concert with the overloading of the rules and style attributes:
# equivalent as example above $xss.'chapter'.'pre' *= '<div class="chapter">'; $xss.'chapter'.'post' *= '</div>';
Sets attributes for a rendering node.
The $name can be an XML element name, or one of the special keywords #document, #text, #comment, #pi or * (for the catch-all element), which will resolve to the corresponding rendering object.
#document
#text
#comment
#pi
*
$xss->set( 'foo' => { rename => 'bar' } ); # same as $xss->element('foo')->set( rename => 'bar' ); $xss->set( '#text' => { filter => { uc shift } } ); # same as $xss->text->set( filter => { uc shift } );
Note that subsequent calls to set() are additive. I.e.:
set()
$xss->set( foo => { pre => 'X' } ); $xss->set( foo => { post => 'Y' } ); # pre is still set to 'X'
If you want to delete an attribute, passes it undef as its value.
undef
Returns the output produced by the application of the stylesheet to the xml document. The xml can be passed as a string, or as a XML::LibXML object. Several XML::LibXML objects can also be passed, in which case the return value will be the concatenation of their transformations.
my $sections = $xss->render( $doc->findnodes( 'section' ) );
The %args is optional, and will defaults to an empty hash if not provided. The reference to %args is also passed to the recursive calls to render() for the children of the processed node, which allows for another way for parent/children nodes to pass information in addition to the stash.
%args
stash
# count the descendents of all nodes $xss->set( '*' => { process => sub { my ( $self, $node, $attrs ) = @_; $attrs->{children}++; return 1; }, content => sub { my ( $self, $node, $attrs ) = @_; my %c_attrs; my $c_ref = \%c_attrs; my $output = $self->render( $node->childNodes, $c_ref ); $attrs->{children} += $c_ref->{children}; $self->{post} = "\n>>> node has " . ($c_ref->{children}||0) . " descendents\n"; return $output; }, } );
Yanick Champoux <yanick@cpan.org>
This software is copyright (c) 2017, 2013, 2011, 2010 by Yanick Champoux.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
To install XML::XSS, copy and paste the appropriate command in to your terminal.
cpanm
cpanm XML::XSS
CPAN shell
perl -MCPAN -e shell install XML::XSS
For more information on module installation, please visit the detailed CPAN module installation guide.