You are viewing a plain text version of this content. The canonical link for it is here.
Posted to axkit-dev@xml.apache.org by jw...@apache.org on 2002/09/13 15:01:09 UTC

cvs commit: xml-axkit/lib/Apache/AxKit/Language/XSP SimpleTaglib.pm

jwalt       2002/09/13 06:01:05

  Modified:    lib/Apache/AxKit/Language/XSP SimpleTaglib.pm
  Added:       demo/AxKit/XSP/Demo SimpleInputAttributes.pm
  Log:
  - applied some documentation and demo patches sent by Ken Neighbors
  - fixed a bug in SimpleTaglib regarding :struct namespaces
  
  Revision  Changes    Path
  1.1                  xml-axkit/demo/AxKit/XSP/Demo/SimpleInputAttributes.pm
  
  Index: SimpleInputAttributes.pm
  ===================================================================
  #!/usr/bin/perl -Tw
  ################################################################################
  package AxKit::XSP::Demo::SimpleInputAttributes;
  # $Id: SimpleInputAttributes.pm,v 1.1 2002/09/13 13:01:05 jwalt Exp $
  
  =pod
  
  =head1 NAME
  
  AxKit::XSP::Demo::SimpleInputAttributes - tag library to demonstrate
  SimpleTaglib Input Attributes
  
  =head1 SYNOPSIS
  
  In http.conf or .htaccess:
  
      AxAddXSPTaglib AxKit::XSP::Demo::SimpleInputAttributes
  
  In XSP page:
  
    <xsp:page xmlns:xsp="http://www.apache.org/1999/XSP/Core"
              xmlns:demo="http://www.nsds.com/NS/xsp/demo/simple-input-attributes"
              indent-result="yes"
    >
  
  =head1 DESCRIPTION
  
  SimpleTaglib (STL) uses Perl function attributes to define how XML
  input gets handled.  This tag library demonstrates the various methods
  available in STL for reading XML input.
  
  =head1 TAG REFERENCE
  
  =cut
  
  ################################################################################
  use strict;
  use Apache::AxKit::Language::XSP::SimpleTaglib;
  use Apache::AxKit::Language::XSP;
  
  $AxKit::XSP::Demo::SimpleInputAttributes::NS =
    "http://www.nsds.com/NS/xsp/demo/simple-input-attributes";
  
  ###############################################################################
  package AxKit::XSP::Demo::SimpleInputAttributes::Handlers;
  
  ###############################################################################
  
  =pod
  
  =head2 attrib
  
      <demo:attrib/>
  
      <demo:attrib parameter="value"/>
  
  This tag demonstrates the SimpleTaglib 'attrib' input attribute, which
  passes XML attributes to the handler function via the attribute hash
  (the third parameter of the handler function, typically named '%attr').
  
  =cut
  
  #------------------------------------------------------------------------------
  sub attrib : attrib(parameter) expr {
      my( $e, $tag, %attr ) = @_;
      if ( not defined $attr{parameter} ) {
  	'"parameter is undef"';
      }
      else {
  	'"parameter is \'' . $attr{parameter} . '\'"';
      }
  }
  
  ###############################################################################
  
  =pod
  
  =head2 child
  
      <demo:child/>
  
      <demo:child>
        <demo:parameter>value</demo:parameter>
      </demo:child>
  
  This tag demonstrates the SimpleTaglib 'child' input attribute.  XML
  input from child tags can be accessed via the '$attr_' variables in
  the code fragment returned by the handler function.
  
  =cut
  
  #------------------------------------------------------------------------------
  sub child : child(parameter) expr {
      my( $e, $tag, %attr ) = @_;
      # Note that q{} is used to quote the code fragment:
      q{
        if ( not defined $attr_parameter ) {
  	  "parameter is undef";
        }
        else {
  	  "parameter is '$attr_parameter'";
        }
       };
  }
  
  ###############################################################################
  
  =pod
  
  =head2 attribOrChild
  
      <demo:attribOrChild/>
  
      <demo:attribOrChild parameter="value"/>
  
      <demo:attribOrChild>
        <demo:parameter>value</demo:parameter>
      </demo:attribOrChild>
  
      <demo:attribOrChild parameter="value1">
        <demo:parameter>value2</demo:parameter>
      </demo:attribOrChild>
  
  This tag demonstrates the SimpleTaglib 'attribOrChild' input
  attribute.  XML input from attributes or child tags can be accessed
  via the '$attr_' variables in the code fragment returned by the
  handler function.  Input from a child tag takes precedence over
  attributes.
  
  =cut
  
  #------------------------------------------------------------------------------
  sub attribOrChild : attribOrChild(parameter) expr {
      my( $e, $tag, %attr ) = @_;
      # Note that q{} is used to quote the code fragment:
      q{
        if ( not defined $attr_parameter ) {
  	  "parameter is undef";
        }
        else {
  	  "parameter is '$attr_parameter'";
        }
       };
  }
  
  ###############################################################################
  
  =pod
  
  =head2 childStruct
  
      <demo:childStruct/>
  
      <demo:childStruct>
        <demo:parameter>value</demo:parameter>
      </demo:childStruct>
  
      <demo:childStruct>
        <demo:parameter>value1</demo:parameter>
        <demo:parameter>value2</demo:parameter>
      </demo:childStruct>
  
  This tag demonstrates the SimpleTaglib 'childStruct' input attribute.
  XML input from child tags can be accessed via the '%_' hash in the
  code fragment returned by the handler function.  Input from a child
  tag takes precedence over attributes.  Note that complex XML
  structures can be passed as input using 'childStruct', but the only
  feature demonstrated here is the use of multiple child tags to set a
  list value for the parameter.  For a more complex example, see
  L<"complex-childStruct">.
  
  =cut
  
  #------------------------------------------------------------------------------
  sub childStruct : childStruct(@parameter) expr {
      my( $e, $tag, %attr ) = @_;
      # Note that q{} is used to quote the code fragment:
      q{
        if ( not defined $_{parameter} ) {
  	  "parameter is undef";
        }
        elsif ( ref $_{parameter} ) {
  	  "parameter is '" . join( "','", @{$_{parameter}} ) . "'";
        }
        else {
  	  "parameter is '$_{parameter}'";
        }
       };
  }
  
  ###############################################################################
  
  =pod
  
  =head2 attrib-or-childStruct
  
      <demo:attrib-or-childStruct/>
  
      <demo:attrib-or-childStruct parameter="value"/>
  
      <demo:attrib-or-childStruct>
        <demo:parameter>value</demo:parameter>
      </demo:attrib-or-childStruct>
  
      <demo:attrib-or-childStruct parameter="value1">
        <demo:parameter>value2</demo:parameter>
      </demo:attrib-or-childStruct>
  
      <demo:attrib-or-childStruct>
        <demo:parameter>value1</demo:parameter>
        <demo:parameter>value2</demo:parameter>
      </demo:attrib-or-childStruct>
  
  This tag demonstrates how to combine the SimpleTaglib 'attrib' and
  'childStruct' input attributes.  XML input from attributes or child
  tags can be accessed via the '%_' hash in the code fragment returned
  by the handler function.  The advantage of this over the
  'attribOrChild' input attribute is that multiple child tags can be
  used to provide a list value for the parameter.
  
  =cut
  
  #------------------------------------------------------------------------------
  sub attrib_or_childStruct : attrib(parameter) childStruct(@parameter) expr {
      my( $e, $tag, %attr ) = @_;
      my $code = '';
      if ( defined $attr{parameter} ) {
  	my $quoted_parameter =
  	  Apache::AxKit::Language::XSP::makeSingleQuoted( $attr{parameter} );
  	$code .= '$_{parameter} = ' . $quoted_parameter .
  	  ' unless defined $_{parameter};';
      }
      # Note that q{} is used to quote the code fragment:
      $code .= q{
  	       if ( not defined $_{parameter} ) {
  		   "parameter is undef";
  	       }
  	       elsif ( ref $_{parameter} ) {
  		   "parameter is '" . join( "','", @{$_{parameter}} ) . "'";
  	       }
  	       else {
  		   "parameter is '$_{parameter}'";
  	       }
  	      };
      $code;
  }
  
  ###############################################################################
  
  =pod
  
  =head2 captureContent
  
      <demo:captureContent/>
  
      <demo:captureContent>text content</demo:captureContent>
  
      <demo:captureContent>
        text content
      </demo:captureContent>
  
  This tag demonstrates the SimpleTaglib 'captureContent' input
  attribute.  The XML text input can be accessed via the '$_' variable
  in the code fragment returned by the handler function.
  
  =cut
  
  #------------------------------------------------------------------------------
  sub captureContent : captureContent expr {
      my( $e, $tag, %attr ) = @_;
      # Note that q{} is used to quote the code fragment:
      q{
        if ( not defined $_ ) {
  	  "content is undef"; # never happens
        }
        else {
  	  "content is '$_'";
        }
       };
  }
  
  ###############################################################################
  
  =pod
  
  =head2 captureContent-and-keepWhitespace
  
      <demo:captureContent-and-keepWhitespace/>
  
      <demo:captureContent-and-keepWhitespace>text content</demo:captureContent-and-keepWhitespace>
  
      <demo:captureContent-and-keepWhitespace>
        text content
      </demo:captureContent-and-keepWhitespace>
  
  This tag demonstrates the SimpleTaglib 'captureContent' and
  'keepWhitespace' input attributes.  The XML text input, including
  surrounding whitespace, can be accessed via the '$_' variable in the
  code fragment returned by the handler function.
  
  =cut
  
  #------------------------------------------------------------------------------
  sub captureContent_and_keepWhitespace : captureContent keepWhitespace expr {
      my( $e, $tag, %attr ) = @_;
      # Note that q{} is used to quote the code fragment:
      q{
        if ( not defined $_ ) {
  	  "content is undef"; # never happens
        }
        else {
  	  "content is '$_'";
        }
       };
  }
  
  ###############################################################################
  
  =pod
  
  =head2 complex-childStruct
  
      <complex-childStruct
        xmlns="http://www.nsds.com/NS/xsp/demo/simple-input-attributes">
          <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">Testeintrag</comment>
          </add>
          <remove target="/test2.html">
              <permission type="user">
                  baz
              </permission>
          </remove>
      </complex-childStruct>
  
  This tag demonstrates complex usage of the SimpleTaglib 'childStruct'
  input attribute.  XML input from child tags can be accessed via the
  '%_' hash in the code fragment returned by the handler function.  This
  example is from the STL documentation (and slightly modified).
  
  =cut
  
  #------------------------------------------------------------------------------
  sub complex_childStruct : childStruct(add{@permission{$type *name} $target $comment(lang)(day)} remove{@permission{$type *name} $target}) expr {
      my( $e, $tag, %attr ) = @_;
      'use Data::Dumper (); "\n" . Data::Dumper->Dump( [ \\%_ ], [ \'*_\' ] )';
  }
  
  ################################################################################
  
  =pod
  
  =head1 AUTHOR
  
  Ken Neighbors <ke...@nsds.com>
  
  =head1 VERSION
  
  $Id: SimpleInputAttributes.pm,v 1.1 2002/09/13 13:01:05 jwalt Exp $
  
  =cut
  
  1;
  
  
  
  1.6       +178 -50   xml-axkit/lib/Apache/AxKit/Language/XSP/SimpleTaglib.pm
  
  Index: SimpleTaglib.pm
  ===================================================================
  RCS file: /home/cvs/xml-axkit/lib/Apache/AxKit/Language/XSP/SimpleTaglib.pm,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- SimpleTaglib.pm	26 Jun 2002 20:12:06 -0000	1.5
  +++ SimpleTaglib.pm	13 Sep 2002 13:01:05 -0000	1.6
  @@ -473,6 +473,7 @@
           }
           die 'data is not a hash ref or DOM fragment!' unless ref($data) eq 'HASH';
           while (my ($key, $val) = each %$data) {
  +            my $outer_namespaces_added = 0;
               if (substr($key,0,1) eq '@') {
                   $key = substr($key,1);
                   die 'attribute value is not a simple scalar!' if ref($val);
  @@ -493,6 +494,7 @@
               $prefix = _lookup_prefix($ns, $namespaces) if $ns and not $prefix;
               if (defined $ns) {
                   unshift @$namespaces, [ $prefix => $ns ];
  +                $outer_namespaces_added++;
               }
               my @data = ref($val) eq 'ARRAY'? @$val:$val;
               foreach my $data (@data) {
  @@ -502,7 +504,7 @@
                       while (my ($key, $val) = each %$data) {
                           if ($key =~ m/^\@xmlns(?::|$)(.*)/) {
                               unshift @$namespaces, [ $1 => $val ];
  -                            ++$namespaces_added;
  +                            $namespaces_added++;
                           }
                       }
                   }
  @@ -523,13 +525,14 @@
                   }
   
                   if (ref($data)) {
  -                    xmlize($document, $elem, [ @$namespaces ], $data);
  +                    xmlize($document, $elem, $namespaces, $data);
                   } else {
                       my $tn = $document->createTextNode($data);
                       $elem->appendChild($tn);
                   }
                   splice(@$namespaces, 0, $namespaces_added) if $namespaces_added; # remove added namespaces
               }
  +            splice(@$namespaces, 0, $outer_namespaces_added) if $outer_namespaces_added; # remove added namespaces
           }
       }
   }
  @@ -785,6 +788,8 @@
   
   __END__
   
  +=pod
  +
   =head1 NAME
   
   Apache::AxKit::XSP::Language::SimpleTaglib - alternate XSP taglib helper
  @@ -815,11 +820,17 @@
   
   A tag "<yourNS:foo>" will trigger a call to sub "foo" during the closing tag event.
   What happens in between can be configured in many ways
  -using function attributes. In the rare cases where some action has to happen during
  +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. Therefore, it is the responsibility of the
  +handler to return a I<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 I<data> to be included in the XML output.
  +
   =head2 Context sensitive handler subs
   
   A sub named "foo___bar" (triple underscore) gets called on the following XML input:
  @@ -829,18 +840,22 @@
   
   =head2 Names, parameters, return values
   
  -Names for subs and variables get created by replacing any non-alphanumeric character in the
  +Names for subs and variables get created by replacing any non-alphanumeric 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()' function
  -attribute. (Try not to confuse these two meanings of 'attribute' - unfortunately XML and
  -Perl both call them that way.) All other declared parameters get converted into local
  -variables with prefix 'attr_'.
  -
  -If a sub has any result attribute ('node', 'expr', etc.), it gets called in list context. If
  -neccessary, returned lists get converted to scalars by joining them without separation. Plain
  -subs (without result attribute) inherit their context and have their return value left unmodified.
  +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 confuse 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 'childStruct', 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 handler as the third parameter.
  +
  +If a sub has an output attribute ('node', 'expr', etc.), the code fragment will be run
  +in list context. If necessary, returned lists get converted 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.
   
   =head2 Precedence
   
  @@ -849,39 +864,54 @@
   
   =over 4
   
  -=item 1. If the innermost tag has a 'childStruct' spec which matches, the internal childStruct
  +=item 1.
  +
  +If the innermost tag has a 'childStruct' spec which matches, the internal childStruct
   handler takes precedence.
   
  -=item 2. Otherwise, if any surrounding tag has a matching 'child' or 'attribOrChild'
  +=item 2.
  +
  +Otherwise, if any surrounding tag has a matching 'child' or 'attribOrChild'
   attribute, the internal handler for the innermost matching tag gets chosen.
   
  -=item 3. Otherwise, the handler sub with the deepest tag hierarchy gets called.
  +=item 3.
  +
  +Otherwise, the handler sub with the deepest tag hierarchy gets called.
   
   =back
   
   =head2 Utility functions
   
  -Apache::AxKit::Language::XSP contains a few handy utility subs:
  +Apache::AxKit::Language::XSP contains a few handy utility subs to help build your code fragment:
   
   =over 4
   
  -=item * start_elem, end_elem, start_attr, end_attr - these create elements and attributes
  +=item 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.
   
  -=item * 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 return values.
  +=item 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.
  +
  +=item makeVariableName
   
  -=item * makeVariableName - creates a valid, readable perl identifier from arbitrary input text.
  +creates a valid, readable perl identifier from arbitrary input text.
   The return values might overlap.
   
   =back
   
  -=head1 AVAILABLE ATTRIBUTES
  +=head1 PERL ATTRIBUTES
   
  -Parameters to attributes get handled as if 'q()' enclosed them. Commas separate arguments, so
  -values cannot contain commas.
  +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.
   
  -=head2 Result attributes
  +=head2 Output attributes
   
   Choose none or one of these to select output behaviour.
   
  @@ -950,13 +980,14 @@
   =head3 C<attrib(name,...)>
   
   Declares C<name> as a (non-mandatory) XML attribute. All attributes declared this way get
  -passed to the handler subs in the attribute hash.
  +passed to your handler sub in the attribute hash (the third argument to your handler).
   
   =head3 C<child(name,...)>
   
   Declares a child tag C<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_C<name>. If the child tag
  -appears more than once, the last value overrides any previous value.
  +contents of the tag, if any, get saved in a local variable named $attr_C<name> and made
  +available to your code fragment. If the child tag appears more than once, the last value
  +overrides any previous value.
   
   =head3 C<attribOrChild(name,...)>
   
  @@ -970,50 +1001,66 @@
   
   =head3 C<captureContent>
   
  -Makes this tag store the enclosed content in '$_' for later retrieval in the handler sub, instead
  +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.
   
   =head3 C<childStruct(spec)>
   
  -Marks this tag to take a complex xml fragment as input. The resulting data structure is available
  -as %_ in the sub. Whitespace is always preserved.
  +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.
   
   C<spec> has the following syntax:
   
   =over 4
   
  -=item 1. A C<spec> consists of a list of tag names, separated by whitespace.
  +=item 1.
   
  -=item 2. Tags may appear in any order.
  +A C<spec> consists of a list of tag names, separated by whitespace (not commas!).
   
  -=item 3. A tag name prefixed by '@' may appear more than once in the xml document. A tag
  +=item 2.
  +
  +Tags may appear in any order.
  +
  +=item 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.
   
  -=item 4. If a '{' follows a tag name, that tag has child tags. A valid C<spec> and a
  +=item 4.
  +
  +If a '{' follows a tag name, that tag has child tags. A valid C<spec> and a
   closing '}' must follow.
   
  -=item 5. A tag name prefixed by '*' does not indicate an input tag but specifies the name
  +=item 5.
  +
  +A tag name prefixed by '*' does not indicate an input tag but specifies the name
   for the text contents of the surrounding tag in the resulting data structure. Such a tag name may
   not bear a '{...}' block.
   
  -=item 6. Any tag without child tags may also appear as attribute of the parent tag.
  +=item 6.
  +
  +Any tag without child tags may also appear as attribute of the parent tag.
   
  -=item 7. A tag name folloewd by one or more parameter specs in parentheses means a hash
  +=item 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 appending a '{...}' block, which would result in a nested hash.
   
  -=item 8. A tag name prefixed by '&' denotes a recursive structure. The tag name must appear
  +=item 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.
   
   =back
   
   Example:
   
  -sub:
  +Given the following handler sub:
   
       set_permission : childStruct(add{@permission{$type *name} $target $comment(lang)(day)} remove{@permission{$type *name} $target})
   
  -XML:
  +and the following XML as input:
   
       <set-permission>
           <add>
  @@ -1036,7 +1083,8 @@
           </remove>
       </set-permission>
   
  -Result: a call to set_permission with %_ set like this:
  +then the local variable '%_' will be made available to your code fragment (returned by
  +your set_permission handler sub).  It will be initialized like this:
   
       %_ = (
           add => {
  @@ -1064,7 +1112,7 @@
   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 a result attribute:
  +node name in an output attribute:
   
     {namespaceURI}name
   
  @@ -1082,7 +1130,7 @@
     node({}name)
   
   This notation for specifying namespaces can also be used in the
  -C<struct> result attribute.  Alternatively, the standard "xmlns" XML
  +C<struct> output attribute.  Alternatively, the standard "xmlns" XML
   attribute may be used to specify namespaces.  For example, the
   following are equivalent:
   
  @@ -1105,7 +1153,7 @@
   "xmlns" XML attributes).
   
   To specify a default namespace for all unqualified node names in the
  -hashref, state it as a parameter to the C<struct> result attribute:
  +hashref, state it as a parameter to the C<struct> output attribute:
   
     struct(namespaceURI)
   
  @@ -1137,17 +1185,20 @@
   prefix:
   
     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.
   
   
  -=head1 EXAMPLE
  +=head1 EXAMPLES
   
  -See AxKit::XSP::Sessions and AxKit::XSP::Auth source code for full-featured 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.
   
   =head1 BUGS AND HINTS
   
  +=head2 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
  @@ -1160,7 +1211,84 @@
   
   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 neccessary.
  +you never use '&' or don't reload the taglib in the running server, this is not necessary.
  +
  +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>
  +
  +=head2 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);';
  +    }
  +
  +=head2 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;
  +    }
   
   =head1 AUTHOR