XML::XSS - Templates and Syntaxic Sugar

August 1st, 2010
XML::XSSXML::XPathScriptPerl

XML::XSS - Templates and Syntaxic Sugar

The first non-development version of XML::XSS has been released on CPAN. The big delta since the last blog entry (xpathscript-reborn) is the re-introduction of templates, and a generous slathering of overloaded shortcuts for stylesheet definitions.

To recap the example I used last time, we were trying to convert the xml snippet

<section title="Introduction">
    <para>This is the first paragraph.</para>
    <para>And here comes the second one.</para>
</section>

into

<h1>Introduction</h1>
    <p class="first_para">This is the first paragraph.</p>
    <p>And here comes the second one.</p>

And we saw that one of the ways of doing this is

$xss->set(
    section => {
        showtag => 0,
        intro   => sub {
            my ( $self, $node ) = @_;
            $self->stash->{seen_para} = 0;    # reset flag
            return '<h1>' . $node->findvalue('@title') . '</h1>';
        },
    } );

$xss->set(
    para => {
        pre   => '<p>',
        post  => '</p>',
        process => sub {
            my ( $self, $node ) = @_;

            $self->set_pre('<p class="first_para">')
                unless $self->{seen_para}++;

            return 1;
        },
    } );

Now, using all the all-new shortcuts available to us, we can perform the same logic with

$xss.'section'.'showtag' *= 0;

$xss.'section'.'intro' x= q{
    <% $r->stylesheet->stash->{seen_para} = 0; %>
    <h1><%@ @title %></h1>
};

$xss.'para'.'style' %= {
    pre  => xsst q{
        <p <%= 'class="first_para"' x !($r->stylesheet->stash->{seen_para}++) %> >
    },
    post => '</p>',
};

Tadah!

Hmm… By the pale green hue that your skin suddenly has developed, I think I should explain this a little bit more.

The overloading part

In order to reduce the amount of typing, I’ve (ab)used the overload pragma to give the stylesheet a CCS-ish flavor. Its basic use is

$xss.$element.$attribute *= $something;

and is simply a shorthand for

$xss->get( $element )->set_$attribute( $something );

Likewise,

$xss.$element.'style' %= {
    pre  => $pre,
    post => $post,
};

is a shorthand for

$xss->set( $element => {
    pre  => $pre,
    post => $post,
});

And, yes, it would have been even better to be able to do

$xss.$element %= {
    pre  => $pre,
    post => $post,
};

but alas it doesn’t seem to be possible, as this mix of overloaded operators confuses the Perl parser to no end. Humbug.

The template

The templates are created via the xsst function automatically exported by XML::XSS. They are fairly simple affairs that have the usual tags (<% ... %> to evaluate some code, and <%= ... %> to evaluate and print), augmented by a couple of XML/stylesheet-centric ones (<%~ $xpath %> to find the nodes matching the xpath and rendering them and <%@ $xpath %> to print out the value returned by the xpath). There are a few other tags available (see the

XML::XSS::Template POD for the thorough listing), but those four are the principal ones.

And as a last bit of magic, the x= operator is overloaded such that

$xss.$element.$attribute x= q{  Hello &lt;%= $r->stylesheet->stash->{name} %> };

is really

$xss.$element.$attribute *= xsst q{  Hello &lt;%= $r->stylesheet->stash->{name} %> };

What Lies Ahead

First, I’ll let the current functionality simmer down and give it a whirl. For one, I’m still not sure if that generous smothering of operator overloads is the most brilliant or dumbest idea I ever had. Using the stylesheet on a few non-trivial test applications should answer that question.

Then, next in line is implementing a sane way to expand stylesheets. And, of course, improving the documentation (which still sucks, albeit slightly less than last time). And after that? … We’ll see when we get there, shall we? :-)