The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

TaglibHelper - module to make it easier to write a taglib

SYNOPSIS

Put this code at the top of your taglib module:

    # this stuff, you change for each taglib
    $NS = 'http://apache.org/xsp/testtaglib/v1';
    @EXPORT_TAGLIB = (
        'func1($arg1)',
        'func2($arg1,$arg2)',
        'func3($arg1,$arg2;$optarg)',
        'func4($arg1,*treearg)',
        'func4($arg1,*treearg):listtag=mylist:itemtag=item',
    );

    # this stuff you don't
    use Apache::AxKit::Language::XSP::TaglibHelper;
    sub parse_char { Apache::AxKit::Language::XSP::TaglibHelper::parse_char(@_); }
    sub parse_start { Apache::AxKit::Language::XSP::TaglibHelper::parse_start(@_); }
    sub parse_end { Apache::AxKit::Language::XSP::TaglibHelper::parse_end(@_); }
    use strict;

...and then edit the $NS and @EXPORT_TAGLIB to reflect your taglib's namespace and list of functions.

DESCRIPTION

The TaglibHelper module is intended to make it much easier to build a taglib module than had previously existed. When you create a library that uses TaglibHelper, you need only to write "regular" functions that take string arguments (optional arguments are supported) and return standard Perl data structures like strings and hashrefs.

FUNCTION SPECIFICATIONS

The @EXPORT_TAGLIB global variable is where you list your exported functions. It is of the format:

    funcname(arguments)[:options]

The <arguments> section contains arguments of the form:

    $argument   a argument that is expected to be a plain string
    *argument   a argument that can take a XML tree in hashref form
    @argument   a argument that is expected to be an array of plain strings
                (i.e. this argument can be called multiple times, like in
                the Sendmail taglib)

These arguments are separated by commas, and optional args are separated from required ones by a semicolon. For example, $field1,$field2;$field3,$field4 has required parameters field1 and field2, and optional parameters field3 and field4.

The options are colon-separated and give extra hints to TaglibHelper in places where the default behavior isn't quite what you want. Currently recognized options are:

    listtag     For functions that return arrays, use the indicated
                wrapper tag for the list instead of <funcname>-list
    itemtag     For functions that return arrays of strings, use the
                indicated wrapper tag for the list items instead of 
                <funcname>-item
    forcearray  For functions that always return an array, you should
                generally set this option to "1". the reason is that
                if your array-returning function only returns one value
                in its array, the result won't be treated as an array
                otherwise.
    conditional The function's return value will not be printed, and
                instead will be used to conditionally execute child
                tags. NOTE that arguments to the function cannot
                be brought in via child tags, but instead must come
                in via attributes.
        isreally        this function specification is actually an alias for
                a perl function of a different name. For example, a specification
                of "person($name):isreally=get_person" allows you to have
                a tag <ns:person name="joe"/> that will resolve to Perl code
                "get_person('Joe')".

EXAMPLE

if you had these two functions:

    sub hello ($) {
        my ($name) = @_;
        return "Hello, $name!";
    }

    sub get_person ($) {
        my ($name) = @_;
        return { 
            person => { 
                name => $name,
                age => 25,
                height => 200,
            }
        }
    }

...and you called them with this xsp fragment:

    <test:hello>
        <test:name>Joe</test:name>
    </test:hello>

    <test:get-person name="Bob"/>

...you would get this XML result:

    Hello, Joe!
    <person>
      <height>200</height>
      <age>25</age>
    <name>Bob</name></person>

If your function returned deeper result trees, with hashes containing hashrefs or something similar, that would be handled fine. There are some limitations with arrays, however, described in the BUGS AND LIMITATIONS section.

STRUCTURED INPUT EXAMPLE

If you wish to send structured data (i.e. not just a scalar) to a taglib function, use "*" instead of "$" for a variable. The input to a taglib function specified as "insert_person($pid,*extra)" might be:

    <test:insert-person pid="123">
        <test:extra>
            <weight>123</weight>
            <friends>   
                <pid>3</pid>
                <pid>5</pid>
                <pid>13</pid>
            </friends>
        </test:extra>
    </test:insert-person>

The function call would be the same as:

    insert_function("123", { 
        weight => 123, 
        friends => [ 3, 5, 13 ]
    });

The <friends> container holds repeating tags, notice, and TaglibHelper figured out automatically that it needs to use an arrayref instead of hashref for the values. But you'll get unexpected results if you mix repeating tags and nonrepeating ones:

        <test:extra>
                <weight>123</weight>
                <friend>3</friend>
                <friend>5</friend>
                <friend>13</friend>
        </test:extra>

Just wrap your singular repeated tags with a plural-form tag, in this case <friends>.

BUGS AND LIMITATIONS

Arrays and arrayrefs are generally difficult to work with because the items within the array have no keys other than the index value. As a result, if you want items within an array to be identified correctly, you must currently make all array items point to a hashref that contains the item's key or you must use the optional arguments to give TaglibHelper enough "hints" to be able to represent the XML tree the way you want.

AUTHOR

Steve Willer, steve@willer.cc

SEE ALSO

AxKit.