=pod =head1 NAME XML::Handler::EasyTree::Generator - Perl extension for generating EasyTree structures =cut package XML::Handler::EasyTree::Generator; use 5.008003; # auto-generated by h2xs, but how low can it go? use strict; use warnings; use diagnostics; use vars qw($default_obj $error $AUTOLOAD); # only make default object once to reduce latency $default_obj = XML::Handler::EasyTree::Generator->new(); our $VERSION = '0.03'; our $revision = '$Id: XML::Handler::EasyTree::Generator.pm,v 1.0 2006/01/16 02:40:00 wren Exp $'; =head1 SYNOPSIS use XML::Handler::EasyTree::Generator; $e = XML::Handler::EasyTree::Generator->new('t' => '_t', 'pi' => '_pi', 'c' => '_c'); $hashref = $e->AUTOLOAD(\%args, @content); $hashref = $e->AUTOLOAD(@content); $hashref = $e->_t(@content); # make a text node $hashref = $e->_c(@content); # make a comment node $hashref = $e->_pi({'target' => $target}, @content); # make a pi node $hashref = $e->_pi($target, @content); # make a pi node $hashref = &XML::Handler::EasyTree::Generator::AUTOLOAD(\%args, @content); =head1 DESCRIPTION This module provides a way to create EasyTree structures on the fly. For more about EasyTree structures see L or L. The interface resembles the autoloader in L. I've chosen to get rid of the leading hyphen for arguments/attributes; if you'd like to see them added in, I suppose I can add a regex to remove them :-) If any errors are encountered the functions will return false and the error will be stored in B<$XML::Handler::EasyTree::Generator::error>. =head2 CAVEAT I've noticed that L (or L or libexpat1) does a few "interesting" things with parsing input. I haven't checked yet to see if L or its dependencies do the same. This module does allow for generating some output that is non-cannonical by those standards, but largely this shouldn't be a problem. Where non-cannonical abilities are granted they'll be noted. One example is unary vs empty tags. The parser reads them in as the same, but you can generate them differently for output. In the potentially forthcoming L (I haven't checked other modules yet) an element node with no content is considered unary whereas one with a null content ('') text node is considered binary but empty. A more dangerous example is generating comment nodes. Comments are usually ignored by the parser. As such, functions that flatten EasyTree structures may croak on comment nodes. =head2 EXPORT None by default. None possible for now. =cut #require Exporter; # #our @ISA = qw(Exporter); # # Items to export into callers namespace by default. Note: do # not export names by default without a very good reason. Use # EXPORT_OK instead. Do not simply export all your public # functions/methods/constants. # # This allows declaration use XML::Handler::EasyTree::Generator ':all'; # If you do not need this, moving things directly into @EXPORT # or @EXPORT_OK will save memory. #our %EXPORT_TAGS = ( 'all' => [ qw() ] ); # #our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); # #our @EXPORT = qw(); =head1 FUNCTIONS =over 4 =item XML::Handler::EasyTree::Generator->new(['t' => $name][, 'pi' => $name][, 'c' => $name]) This method creates a new object which lets you use the autoloader below in object-oriented fashion. By default the autoloader will create element nodes. Since tag names are extensible, we need special names for other node types. Rather than enforcing a specific special name, you can specify what names you would like to be set aside for text, parser-instruction, and comment nodes. By default these are '_t', '_pi', and '_c' respectively. With the function oriented autoloader there's no way to change these defaults. N.B. comment nodes are non-cannonical and may cause functions that turn EasyTree structures into XML text to croak. =cut ####### # NEW # ####### sub new { my $class = shift; my %args = @_; $args{'t'} ||= '_t'; $args{'pi'} ||= '_pi'; $args{'c'} ||= '_c'; my $this = \%args; bless $this, $class; return $this; } =item $easytreetools_obj->AUTOLOAD([\%args,] @content) =item &XML::Handler::EasyTree::Generator::AUTOLOAD([\%args,] @content) This function set allows you to create an EasyTree node in a manner similar to that used in L for creating HTML nodes. It can be used either as a function or as a method. The initial hashref of attribute/value pairs is optional. If it is present for text or comment nodes it is discarded. If it is present for PI nodes, the 'target' value is taken if present, all other values are discarded. If the target cannot be taken from the %args hash, the first element of @content is assumed to be the target. For element nodes the @content array can contain either scalars which are interperated as text nodes, or can contain hashrefs which are assumed to be EasyTree nodes. For non-element nodes the @content array is join('')ed, sans the target for PI nodes as appropriate. If you want to use a namespace for an element, surround it with underscores as so: C<_namespace__tagname()> and the function will deal with the rest. Single underscores are allowed in namespaces or tagnames; double underscores are not allowed in namespaces. It's convoluted, but it doesn't severely limit your choices of tag names and allows namespaces so we can deal with it. =cut ############ # AUTOLOAD # ############ sub AUTOLOAD { # declare and define variables my $program = $AUTOLOAD; $program =~ s/(.*):://; # remove package my $this; if (ref $_[0] eq $1) { $this = shift; } else { $this = $default_obj; } $program =~ s/^_(.*?)__/$1:/; # resolve XML namespaces my $args = {}; if (ref $_[0] eq 'HASH') { $args = shift; } my @content = @_; my $return = {}; # generate EasyTree text node if ($program eq $this->{'t'}) { $return = {'type' => 't', 'content' => join('',@content)}; # generate EasyTree comment node } elsif ($program eq $this->{'c'}) { $return = {'type' => 'c', 'content' => join('',@content)}; # generate EasyTree PI node } elsif ($program eq $this->{'pi'}) { my $target; if (exists $$args{'target'}) { $target = $$args{'target'}; } else { $target = shift @content; } return &error("Must specify a target for PI nodes") unless $target; $return = { 'type' => 'p', 'target' => $target, 'content' => join('',@content) }; # generate EasyTree element node } else { $return = { 'type' => 'e', 'name' => $program, 'attrib' => \%$args, 'content' => [] }; foreach (@content) { my $content; if (ref \$_ eq 'SCALAR') { $content = {'type' => 't', 'content' => $_}; } elsif (ref $_ eq 'HASH') { # this should be an EasyTree node, # but there's no error checking $content = $_; } else { return &error("Autoloading error with content element '$_'"); } push @{$$return{'content'}}, $content; } } # end if (node type) return $return; } ######### # ERROR # ######### sub error { # Usage: `or return &error($error);` $error = join('', @_); return; } =back =head1 BUGS AND ISSUES Actual resolved namespaces aren't yet supported. Namespaces lead to a node with the name 'namespace:tagname' just as if you have namespace resolving turned off. =head1 SEE ALSO L, L, L Not specific to this module, but post discussion to L =head1 AUTHOR wren ng thornton, Ewren@cpan.orgE L =head1 COPYRIGHT AND LICENSE Copyright (C) 2004~2006 by wren ng thornton. ALL RIGHTS RESERVED. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.3 or, at your option, any later version of Perl 5 you may have available. =head1 Version History =over 4 =item B =over 4 =item * Tried better to make v0.02 updates consistent in meta files. (v0.03) =item * Updated author's name and contact info. (v0.02) =item * Initial release. (v0.01) =back =back =cut 1; __END__