NAME

PXML::Preserialize - faster PXML templating through preserialization

SYNOPSIS

    use PXML::Preserialize qw(pxmlfunc pxmlpre);
    use PXML::XHTML qw(A B);

    my $link_normal= sub {
        my ($href,$body)=@_;
        A {href=> $href}, $body
    };

    my $link_fast= pxmlfunc {
        my ($href,$body)=@_; # can take up to 10[?] arguments.
        A {href=> $href}, $body
    };

    # the `2` is the number of arguments
    my $link_fast2= pxmlpre 2, $link_normal;

    # these expressions are all returning the same result, but the second
    # and third are (supposedly) evaluated faster than the first:
    is $link_normal->("http://foo", [B("Foo"), "Bar"])->string,
       '<a href="http://foo"><b>Foo</b>Bar</a>';
    is $link_fast->("http://foo", [B("Foo"), "Bar"])->string,
       '<a href="http://foo"><b>Foo</b>Bar</a>';
    is $link_fast2->("http://foo", [B("Foo"), "Bar"])->string,
       '<a href="http://foo"><b>Foo</b>Bar</a>';

DESCRIPTION

PXML represents every XML/HTML element as an individual Perl object, and both building up a PXML tree and serializing it is somewhat costly.

And even if only a few strings change in a (sub)tree, a new tree instance needs to be created and serialized for every set of those strings.

This overhead can be eliminated by pre-serializing the segments of the tree that don't change.

This module offers `pxmlpre`, a function that takes a user supplied function which maps some number of arguments to a PXML tree with those arguments inserted, and returns a function that maps those same arguments to an array with preserialized fragments and the (escaped) argument values so that the PXML serialization functions don't have any work to do except for printing the fragments and values.

With the example from the synopsis:

 &$link_normal("foo","bar")

returns a PXML element with name "a", a hash `{href=> "foo"}` as attributes, and "bar" as the body. `->string` walks over the element and hash and body and turns all parts into the proper XML syntax.

 &$link_fast2("foo","bar")

returns

 bless [ $fragment1, "foo", $fragment2, "$bar", $fragment3 ], "PXML::Body"

where $fragment1 is the string '<a href="' blessed to `PXML::Preserialize::Serialized`, which has a `pxml_serialized_body_string` method that returns the unmodified string, which the serializer finds and calls (this is the currently implemented way to add fragments to a PXML data structure and have the serializer output them unescaped).

The fragments are built by running the user-supplied function with trial arguments and then serializing the resulting tree, breaking up the serialized string where the arguments are found, then returning a closure that returns an array with both the constant pieces and new arguments.

RESTRICTIONS

The user-supplied functions need to heed the following restrictions:

  • be pure

  • must not contain branching (if/else etc.)

    The arguments are not allowed to influence the structure of the returned PXML tree, only the contents at the ever same spots.

  • must insert the arguments into the result unmodified

    The arguments, if they are used at all, must be inserted into the tree unmodified. Even appending or prepending strings is not allowed (use a wrapper array to put values before/after instead). To guard against such errors, the argument values that are passed during the preserialization step throw an error if they are stringified etc.

Also, the values returned by `pxmlpre`'d functions can not be processed with e.g. functions in `PXML::Util`, or at least those won't find the elements in the parts that have been pre-serialized.

NOTE

This is alpha software! Read the status section in the package README or on the website.