The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
NAME
    XML::XSS - XML stylesheet system

VERSION
    version 0.3.1

SYNOPSIS
        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

DESCRIPTION
    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" is a rewrite of XML::XPathScript, which was initially part of
    the AxKit framework.

  The XML Document
    "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 );

  Stylesheet Rules
    "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.

  Rules Style Attributes
    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()".

        $css->set( 'foo' => {
            pre => '[[[',         
            post => sub {        
                my ( $self, $node, $args ) = @_;
                return $node->findvalue( '@bar' );
            }
        } );

  Modifying Rules While Rendering
    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;
            }
        } );

ATTRIBUTES
  document
    The document rule. Note that this matches against the
    "XML::LibXML::Document" node, not the root element node of the document.

   document()
    Attribute getter.

  text
    The text rule.

   text()
    Attribute getter.

   set_text( ... )
    Shortcut for

        $xss->text->set( ... );

   clear_text()
    Shortcut for

        $xss->text->clear;

  comment
    The comment rule.

   comment()
    Attribute getter.

   set_comment( ... )
    Shortcut for

        $xss->comment->set( ... )

  elements
    The collection of user-defined element rules.

   element( $name )
    Returns the XML::XSS::Element node associated to the tag $name. If the
    element didn't already exist, it is automatically created.

        my $elt = $xss->element( 'foo' );  # element for <foo>
        $elt->set( pre => '[foo]' );

  catchall_element
    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' } );

   catchall_element()
    The attribute getter.

  stash
    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 => \&section_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.

   stash()
    The attribute getter.

   clear_stash()
    Clear the stash.

OVERLOADING
  Concatenation (.)
    The concatenation operator is overloaded to behave as an alias for
    "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>';

METHODS
  set( $element_1 => \%attrs, $element_2 => \%attrs_2, ... )
    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.

        $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.:

        $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.

  render( $xml, \%args )
    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".

        # 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;
                },
            } );

AUTHOR
    Yanick Champoux <yanick@cpan.org>

COPYRIGHT AND LICENSE
    This software is copyright (c) 2011 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.