DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 

SimpleTaglib(3)





NAME

       Apache::AxKit::XSP::Language::SimpleTaglib - alternate XSP taglib
       helper


SYNOPSIS

           package Your::XSP::Package;
           use Apache::AxKit::Language::XSP::SimpleTaglib;

           ... more initialization stuff, start_document handler, utility functions, whatever
               you like, but no parse_start/end handler needed - if in doubt, just leave empty ...

           package Your::XSP::Package::Handlers;

           sub some_tag : attrib(id) attribOrChild(some-param) node(result) keepWhitespace {
               my ($e, $tag, %attr) = @_;
               return 'do_something($attr_some_param,'.$attr{'id'}.');';
           }


DESCRIPTION

       This taglib helper allows you to easily write tag handlers with most of
       the common behaviours needed. It manages all 'Design Patterns' from the
       XSP man page plus several other useful tag styles.

       Simple handler subs

       A tag "<yourNS:foo>" will trigger a call to sub "foo" during the clos-
       ing tag event.  What happens in between can be configured in many ways
       using Perl function attributes. In the rare cases where some action has
       to happen during the opening tag event, you may provide a sub
       "foo__open" (double underscore) which will be called at the appropriate
       time. Usually you would only do that for 'if'- style tags which enclose
       some block of code.

       It is important to understand that your tag handler is called during
       the XSP parse stage, when the XSP script is being constructed. There-
       fore, it is the responsibility of the handler to return a Perl code
       fragment to be appended to the XSP script, as shown above. Contrast
       this behaviour to TaglibHelper, where the handler is called when the
       XSP script is being run, and it returns data to be included in the XML
       output.

       Context sensitive handler subs

       A sub named "foo___bar" (triple underscore) gets called on the follow-
       ing XML input: "<yourNS:foo><yourNS:bar/></yourNS:foo>". Handler subs
       may have any nesting depth.  The rule for opening tag handlers applies
       here as well. The sub name must represent the exact tag hierarchy
       (within your namespace).

       Names, parameters, return values

       Names for subs and variables get created by replacing any non-alphanu-
       meric characters in the original tag or attribute to underscores. For
       example, 'get-id' becomes 'get_id'.

       The called subs get passed 3 parameters: The parser object, the tag
       name, and an attribute hash. This hash only contains XML attributes
       declared using the 'attrib()' Perl function attribute. (Try not to con-
       fuse these two meanings of 'attribute' - unfortunately XML and Perl
       both call them that way.) The other declared parameters get converted
       into local variables with prefix 'attr_', or, in the case of 'child-
       Struct', converted into the '%_' hash. These local variables are only
       available inside your code fragment which becomes part of the XSP
       script, unlike the attribute hash which is passed directly to your han-
       dler as the third parameter.

       If a sub has an output attribute ('node', 'expr', etc.), the code frag-
       ment will be run in list context. If necessary, returned lists get con-
       verted to scalars by joining them without separation. Code fragments
       from plain subs (without an output attribute) inherit their context and
       have their return value left unmodified.

       Precedence

       If more than one handler matches a tag, the following rules determine
       which one is chosen.  Remember, though, that only tags in your names-
       pace are considered.

       1.  If the innermost tag has a 'childStruct' spec which matches, the
           internal childStruct handler takes precedence.

       2.  Otherwise, if any surrounding tag has a matching 'child' or 'attri-
           bOrChild' attribute, the internal handler for the innermost match-
           ing tag gets chosen.

       3.  Otherwise, the handler sub with the deepest tag hierarchy gets
           called.

       Utility functions

       Apache::AxKit::Language::XSP contains a few handy utility subs to help
       build your code fragment:

       start_elem, end_elem, start_attr, end_attr
           these create elements and attributes in the output document. Call
           them just like you call start_expr and end_expr.

       makeSingleQuoted
           given a scalar as input, it returns a scalar which yields the exact
           input value when evaluated; handy when using unknown text as-is in
           code fragments.

       makeVariableName
           creates a valid, readable perl identifier from arbitrary input
           text.  The return values might overlap.


PERL ATTRIBUTES

       Perl function attributes are used to define how XML output should be
       generated from your code fragment and how XML input should be presented
       to your handler.  Note that parameters to attributes get handled as if
       'q()' enclosed them (explicit quote marks are not needed). Furthermore,
       commas separate parameters (except for childStruct), so a parameter
       cannot contain a comma.

       Output attributes

       Choose none or one of these to select output behaviour.

       "expr"

       Makes this tag behave like an '<xsp:expr>' tag, creating text nodes or
       inline text as appropriate.  Choose this if you create plain text which
       may be used everywhere, including inside code. This attribute has no
       parameters.

       "node(name)"

       Makes this tag create an XML node named "name". The tag encloses all
       content as well as the results of the handler sub.  Choose this if you
       want to create one XML node with all your output.

       "nodelist(name)"

       Makes this tag create a list of XML nodes named "name". The tag(s) do
       not enclose content nodes, which become preceding siblings of the gen-
       erated nodes. The return value gets converted to a node list by enclos-
       ing each element with an XML node named "name".  Choose this if you
       want to create a list of uniform XML nodes with all your output.

       "exprOrNode(name,attrname,attrvalue)"

       Makes this tag behave described under either 'node()' or 'expr',
       depending on the value of XML attribute "attrname". If that value
       matches "attrvalue", it will work like 'node()', otherwise it will work
       like 'expr'. "attrname" defaults to 'as', "attrvalue" defaults to
       'node', thus leaving out both parameters means that 'as="node"' will
       select 'node()' behaviour.  Choose this if you want to let the XSP
       author decide what to generate.

       "exprOrNodelist(name,attrname,attrvalue)"

       Like exprOrNode, selecting between 'expr' and 'nodelist()' behaviour.

       "struct"

       Makes this tag create a more complex XML fragment. You may return a
       single hashref or an array of hashrefs, which get converted into an XML
       structure. Each hash element may contain a scalar, which gets converted
       into an XML tag with the key as name and the value as content. Alterna-
       tively, an element may contain an arrayref, which means that an XML tag
       encloses each single array element.  Finally, you may use hashrefs in
       place of scalars to create substructures. To create attributes on tags,
       use a hashref that contain the attribute names prefixed by '@'. A ''
       (empty string) as key denotes the text contents of that node.

       You can also use a XML::LibXML::Document or XML::LibXML::Node object in
       place of a hashref. You can, for example, simply return an
       XML::LibXML::Document object and it gets inserted at the current loca-
       tion. You may also return an array of documents/nodes, and you may even
       mix plain hashrefs with DOM objects as you desire.

       In an expression context, passes on the unmodified return value.

       Other output attributes

       These may appear more than once and modify output behaviour.

       "nodeAttr(name,expr,...)"

       Adds an XML attribute named "name" to all generated nodes. "expr" gets
       evaluated at run time.  Evaluation happens once for each generated
       node. Of course, this tag only makes sense with 'node()' type handlers.

       Input attributes

       These tags specify how input gets handled. Most may appear more than
       once, if that makes sense.

       "attrib(name,...)"

       Declares "name" as a (non-mandatory) XML attribute. All attributes
       declared this way get passed to your handler sub in the attribute hash
       (the third argument to your handler).

       "child(name,...)"

       Declares a child tag "name". It always lies within the same namespace
       as the taglib itself. The contents of the tag, if any, get saved in a
       local variable named $attr_"name" and made available to your code frag-
       ment. If the child tag appears more than once, the last value overrides
       any previous value.

       "attribOrChild(name,...)"

       Declares an attribute or child tag named "name". A variable is created
       just like for 'child()', containing the attribute or child tag con-
       tents. If both appear, the contents of the child tag take precedence.

       "keepWhitespace"

       Makes this tag preserve contained whitespace.

       "captureContent"

       Makes this tag store the enclosed content in '$_' for later retrieval
       in your code fragment instead of adding it to the enclosing element.
       Non-text nodes will not work as expected.

       "childStruct(spec)"

       Marks this tag to take a complex XML fragment as input. The resulting
       data structure is available as %_ in your code fragment. Whitespace is
       always preserved.

       "spec" has the following syntax:

       1.  A "spec" consists of a list of tag names, separated by whitespace
           (not commas!).

       2.  Tags may appear in any order.

       3.  A tag name prefixed by '@' may appear more than once in the XML
           document. A tag name prefixed by '$' or without any prefix may only
           appear once.

       4.  If a '{' follows a tag name, that tag has child tags. A valid
           "spec" and a closing '}' must follow.

       5.  A tag name prefixed by '*' does not indicate an input tag but spec-
           ifies the name for the text contents of the surrounding tag in the
           resulting data structure. Such a tag name may not bear a '{...}'
           block.

       6.  Any tag without child tags may also appear as attribute of the par-
           ent tag.

       7.  A tag name followed by one or more parameter specs in parentheses
           means a hash gets created with the value of the corresponding
           attribute (or child tag) as key. This usage does not forbid append-
           ing a '{...}' block, which would result in a nested hash.

       8.  A tag name prefixed by '&' denotes a recursive structure. The tag
           name must appear as the name of one of the surrounding
           '{...}'-blocks. The innermost matching block gets chosen.

       Example:

       Given the following handler sub:

           set_permission : childStruct(add{@permission{$type *name} $target $comment(lang)(day)} remove{@permission{$type *name} $target})

       and the following XML as input:

           <set-permission>
               <add>
                   <permission type="user">
                       foo
                   </permission>
                   <permission>
                       <type>group</type>
                       bar
                   </permission>
                   <target>/test.html</target>
                   <comment lang="en" day="Sun">Test entry</comment>
                   <comment lang="en" day="Wed">Test entry 2</comment>
                   <comment><lang>de</lang>Testeintrag</comment>
               </add>
               <remove target="/test2.html">
                   <permission type="user">
                       baz
                   </permission>
               </remove>
           </set-permission>

       then the local variable '%_' will be made available to your code frag-
       ment (returned by your set_permission handler sub).  It will be ini-
       tialized like this:

           %_ = (
               add => {
                   permission => [
                       { type => "user", name => 'foo' },
                       { type => "group", name => 'bar' },
                   ],
                   target => '/test.html',
                   comment => {
                       'en' => { 'Sun' => 'Test entry', 'Wed' => 'Test entry 2' },
                       'de' => { '' => 'Testeintrag' },
                   }
               },
               remove => {
                   permission => [
                       { type => "user", name => 'baz' },
                   ],
                   target => '/test2.html',
               },
           );


XML NAMESPACES

       By default, all output element nodes are placed in the same namespace
       as the tag library.  To specify a different namespace or no namespace,
       the desired namespace can be placed within curly braces before the node
       name in an output attribute:

         {namespaceURI}name

       To specify a prefix, place it after the namespace:

         {namespaceURI}prefix:name

       For example, to create an XML node named "otherNS:name" and associate
       the prefix 'otherNS' with the namespace 'http://mydomain/NS/other/v1':

         node({http://mydomain/NS/other/v1}otherNS:name)

       To create an XML node with no namespace, use an empty namespace:

         node({}name)

       This notation for specifying namespaces can also be used in the
       "struct" output attribute.  Alternatively, the standard "xmlns" XML
       attribute may be used to specify namespaces.  For example, the follow-
       ing are equivalent:

         sub sample_struct : struct {
           return "{ '{http://mydomain/NS/other/v1}otherNS:name' => 'value' }";
         }

         sub sample_struct : struct {
           return q{{
               'otherNS:name' =>
               { '@xmlns:otherNS' => 'http://mydomain/NS/other/v1',
                 '' => 'value' }
           }};
         }

       Namespace scoping in the hashref is patterned after XML documents.  You
       may refer to previously declared namespaces by using the same prefix,
       and you may override previously declared namespaces with new declara-
       tions (either with the curly-braced notation or by using "xmlns" XML
       attributes).

       To specify a default namespace for all unqualified node names in the
       hashref, state it as a parameter to the "struct" output attribute:

         struct(namespaceURI)

       You may also specify a prefix:

         struct({namespaceURI}prefix)

       For example, the following is equivalent to the previous example:

         sub sample_struct : struct({http://mydomain/NS/other/v1}otherNS) {
           return "{ 'name' => 'value' }";
         }

       To turn off the default namespace for all node names, use an empty
       namespace:

         sub sample_struct : struct({}) {
           return "{ 'name' => 'value' }";
         }

       By default, XML attributes created with the "nodeAttr" output attribute
       are not in a namespace.  The curly-braced notation can be used to spec-
       ify a namespace.  For example:

         nodeAttr({http://www.w3.org/TR/REC-html40}html:href,'http://www.axkit.org/')

       If you are specifying more than one attribute in the same namespace,
       you can refer to previously declared namespaces by using the same pre-
       fix:

         nodeAttr({http://www.w3.org/TR/REC-html40}html:href,'http://www.axkit.org/',html:class,'link')

       A prefix is required to associate a namespace with an attribute.
       Default namespaces (those without a prefix) do not apply to attributes
       and are ignored.


EXAMPLES

       Refer to the Demo tag libraries included in the AxKit distribution and
       look at the source code of AxKit::XSP::Sessions and AxKit::XSP::Auth
       for full-featured examples.


BUGS AND HINTS

       Miscellaneous

       Because of the use of perl attributes, SimpleTaglib will only work with
       Perl 5.6.0 or later.  This software is already tested quite well and
       works for a number of simple and complex taglibs. Still, you may have
       to experiment with the attribute declarations, as the differences can
       be quite subtle but decide between 'it works' and 'it doesn't'. XSP can
       be quite fragile if you start using heavy trickery.

       If some tags don't work as expected, try surrounding the offending tag
       with <xsp:content>, this is a common gotcha (but correct and intended).
       If you find yourself needing <xsp:expr> around a tag, please contact
       the author, as that is probably a bug.

       If you use the '&' flag of childStruct and are reloading your taglib
       through Apache::StatINC or a similar method, consider installing the
       'WeakRef' module from CPAN to prevent memory leaks. If you never use
       '&' or don't reload the taglib in the running server, this is not nec-
       essary.

       TODO: to be fixed: childStruct currently does not allow hash keys to be
       child nodes, they must be attributes of their parent node. For example,
       given childStruct(text(lang)), this is valid: <text
       lang="en">foo</text> but this is not: <text><lang>en</lang>foo</text>

       Request-time handler

       TODO: This shall be enhanced in a future release.

       If you pine for the TaglibHelper-style handlers that get called at
       request time, and you do not need the flexibility of custom-generated
       code fragments provided by SimpleTaglib, you can define a subroutine in
       your tag library to be called at request time instead of at parse time.
       Just place a call to your subroutine inside the code fragment returned
       by your handler.  You can even pass it some request-time variables such
       as $r and $cgi.  For example,

           package Your::XSP::Package;
           use Apache::AxKit::Language::XSP::SimpleTaglib;

           sub some_tag {
               my($r, $cgi, $some_param) = @_;
               # define code here to be run at request time
           }

           package Your::XSP::Package::Handlers;

           sub some_tag : attribOrChild(some-param) node(result) {
               'Your::XSP::Package::some_tag($r,$cgi,$attr_some_param);';
           }

       Using attrib and childStruct together

       TODO: to be fixed.

       You may need a list-valued parameter to be specified by XML child tags
       for your tag handler, but you also want the option that a single value
       can be passed in as an XML attribute.  For example:

         <yourNS:some_tag>
           <yourNS:format>XML</yourNS:format>
           <yourNS:format>HTML</yourNS:format>
           <yourNS:format>PDF</yourNS:format>
         </yourNS:some_tag>

         <yourNS:some_tag format="XML"/>

       The 'attribOrChild' Perl attribute will not suffice here because the
       child tag overwrites the previous value each time instead of creating a
       list (format will be set to 'PDF').  What you need is a combination of
       'attrib' and 'childStruct':

           sub some_tag : attrib(format) childStruct(@format) node(result) {
               my ($e, $tag, %attr) = @_;
               my $code = '';
               if ( defined $attr{format} ) {
                   my $quoted = Apache::AxKit::Language::XSP::makeSingleQuoted($attr{format});
                   $code .= '$_{format} = ' . $quoted . ' unless defined $_{format};';
               }
               $code .= 'Your::XSP::Package::some_tag($r,$cgi,%_);';
               $code;
           }

       This technique can be generalized to support any number of parameters.
       In your handler, iterate over the '%attr' hash (defined by 'attrib')
       and merge the values into the '%_' hash (defined by 'childStruct')
       inside your code fragment.  Remember that parameters defined in the
       childStruct attribute are separated by spaces, not commas.

           sub some_tag : attrib(format,option) childStruct(@format @option) node(result) {
               my ($e, $tag, %attr) = @_;
               my $code = '';
               while ( my($key, $value) = each %attr ) {
                   next unless defined $value;
                   $value = Apache::AxKit::Language::XSP::makeSingleQuoted($value);
                   $code .= "\$_{'_$key'} = $value unless defined \$_{'_$key'};\n"
               }
               $code .= 'Your::XSP::Package::some_tag($r,$cgi,%_);';
               $code;
           }


AUTHOR

       Jrg Walter <jwalt@cpan.org>


COPYRIGHT

       All rights reserved. This program is free software; you can redis-
       tribute it and/or modify it under the same terms as AxKit itself.


SEE ALSO

       AxKit, Apache::AxKit::Language::XSP, Apache::AxKit::Lan-
       guage::XSP::TaglibHelper


perl v5.8.6 Apache::AxKit::Language::XSP::SimpleTaglib(3)



Man(1) output converted with man2html