[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Debian JP master SVN www commits (rev.242)



=======================================================
Repository: /org/svn.debian.or.jp/repos
  Revision: 242
  Commiter: kmuto
      Date: 2007-04-01 20:07:38 +0900 (日, 01  4月 2007)
=======================================================
Log:

commit XML plugin for sid users.

=======================================================
Changed:

A   www/trunk/XML/
A   www/trunk/XML/DOM.pm
A   www/trunk/XML/README
A   www/trunk/XML/RSS.pm
A   www/trunk/XML/Simple.pm
A   www/trunk/XML/Style.pm
A   www/trunk/XML/XPath.pm

Added: www/trunk/XML/DOM.pm
===================================================================
--- www/trunk/XML/DOM.pm	                        (rev 0)
+++ www/trunk/XML/DOM.pm	2007-04-01 11:07:38 UTC (rev 242)
@@ -0,0 +1,841 @@
+#============================================================= -*-Perl-*-
+#
+# Template::Plugin::XML::DOM
+#
+# DESCRIPTION
+#
+#   Simple Template Toolkit plugin interfacing to the XML::DOM.pm module.
+#
+# AUTHORS
+#   Andy Wardley   <abw@xxxxxxx>
+#   Simon Matthews <sam@xxxxxxxxxxxxxxxxx>
+#
+# COPYRIGHT
+#   Copyright (C) 2000 Andy Wardley, Simon Matthews.  All Rights Reserved.
+#
+#   This module is free software; you can redistribute it and/or
+#   modify it under the same terms as Perl itself.
+#
+#----------------------------------------------------------------------------
+#
+# $Id: DOM.pm,v 2.55 2004/01/30 19:33:34 abw Exp $
+#
+#============================================================================
+
+package Template::Plugin::XML::DOM;
+
+require 5.004;
+
+use strict;
+use Template::Plugin;
+use XML::DOM;
+
+use base qw( Template::Plugin );
+use vars qw( $VERSION $DEBUG );
+
+$VERSION  = 2.6;
+$DEBUG    = 0 unless defined $DEBUG;
+
+
+#------------------------------------------------------------------------
+# new($context, \%config)
+#
+# Constructor method for XML::DOM plugin.  Creates an XML::DOM::Parser
+# object and initialise plugin configuration.
+#------------------------------------------------------------------------
+
+sub new {
+    my $class   = shift;
+    my $context = shift;
+    my $args    = ref $_[-1] eq 'HASH' ? pop(@_) : { };
+    
+    my $parser ||= XML::DOM::Parser->new(%$args)
+	|| return $class->_throw("failed to create XML::DOM::Parser\n");
+
+    # we've had to deprecate the old usage because it broke things big time
+    # with DOM trees never getting cleaned up.
+    return $class->_throw("XML::DOM usage has changed - you must now call parse()\n")
+	if @_;
+    
+    bless { 
+	_PARSER  => $parser,
+	_DOCS    => [ ],
+	_CONTEXT => $context,
+	_PREFIX  => $args->{ prefix  } || '',
+	_SUFFIX  => $args->{ suffix  } || '',
+	_DEFAULT => $args->{ default } || '',
+	_VERBOSE => $args->{ verbose } || 0,
+	_NOSPACE => $args->{ nospace } || 0,
+	_DEEP    => $args->{ deep    } || 0,
+    }, $class;
+}
+
+
+#------------------------------------------------------------------------
+# parse($content, \%named_params)
+#
+# Parses an XML stream, provided as the first positional argument (assumed
+# to be a filename unless it contains a '<' character) or specified in 
+# the named parameter hash as one of 'text', 'xml' (same as text), 'file'
+# or 'filename'.
+#------------------------------------------------------------------------
+
+sub parse {
+    my $self   = shift;
+    my $args   = ref $_[-1] eq 'HASH' ? pop(@_) : { };
+    my $parser = $self->{ _PARSER };
+    my ($content, $about, $method, $doc);
+
+    # determine the input source from a positional parameter (may be a 
+    # filename or XML text if it contains a '<' character) or by using
+    # named parameters which may specify one of 'file', 'filename', 'text'
+    # or 'xml'
+
+    if ($content = shift) {
+	if ($content =~ /\</) {
+	    $about  = 'xml text';
+	    $method = 'parse';
+	}
+	else {
+	    $about = "xml file $content";
+	    $method = 'parsefile';
+	}
+    }
+    elsif ($content = $args->{ text } || $args->{ xml }) {
+	$about = 'xml text';
+	$method = 'parse';
+    }
+    elsif ($content = $args->{ file } || $args->{ filename }) {
+	$about = "xml file $content";
+	$method = 'parsefile';
+    }
+    else {
+	return $self->_throw('no filename or xml text specified');
+    }
+
+    # parse the input source using the appropriate method determined above
+    eval { $doc = $parser->$method($content) } and not $@
+	or return $self->_throw("failed to parse $about: $@");
+
+    # update XML::DOM::Document _UserData to contain config details
+    $doc->[ XML::DOM::Node::_UserData ] = {
+	map { ( $_ => $self->{ $_ } ) } 
+	qw( _CONTEXT _PREFIX _SUFFIX _VERBOSE _NOSPACE _DEEP _DEFAULT ),
+    };
+
+    # keep track of all DOM docs for subsequent dispose()
+#    print STDERR "DEBUG: $self adding doc: $doc\n"
+#	if $DEBUG;
+
+    push(@{ $self->{ _DOCS } }, $doc);
+
+    return $doc;
+}
+
+
+#------------------------------------------------------------------------
+# _throw($errmsg)
+#
+# Raised a Template::Exception of type XML.DOM via die().
+#------------------------------------------------------------------------
+
+sub _throw {
+    my ($self, $error) = @_;
+    die (Template::Exception->new('XML.DOM', $error));
+}
+
+
+#------------------------------------------------------------------------
+# DESTROY
+#
+# Cleanup method which calls dispose() on any and all DOM documents 
+# created by this object.  Also breaks any circular references that
+# may exist with the context object.
+#------------------------------------------------------------------------
+
+sub DESTROY {
+    my $self = shift;
+
+    # call dispose() on each document produced by this parser
+    foreach my $doc (@{ $self->{ _DOCS } }) {
+#	print STDERR "DEBUG: $self destroying $doc\n"
+#	    if $DEBUG;
+	if (ref $doc) {
+#	    print STDERR "disposing of $doc\n";
+	    undef $doc->[ XML::DOM::Node::_UserData ]->{ _CONTEXT };
+	    $doc->dispose();
+	}
+    }
+    delete $self->{ _CONTEXT };
+    delete $self->{ _PARSER };
+}
+
+
+
+#========================================================================
+package XML::DOM::Node;
+#========================================================================
+
+
+#------------------------------------------------------------------------
+# present($view)
+#
+# Method to present node via a view (supercedes all that messy toTemplate
+# stuff below).
+#------------------------------------------------------------------------
+
+sub present {
+    my ($self, $view) = @_;
+
+    if ($self->getNodeType() == XML::DOM::ELEMENT_NODE) {
+	# it's an element
+	$view->view($self->getTagName(), $self);
+    }
+    else {
+	my $text = $self->toString();
+	$view->view('text', $text);
+    }
+}
+
+sub content {
+    my ($self, $view) = @_;
+    my $output = '';
+    foreach my $node (@{ $self->getChildNodes }) {
+	$output .= $node->present($view);
+
+# abw test passing args, Aug 2001
+#	$output .= $view->print($node);
+    }
+    return $output;
+}
+
+
+#------------------------------------------------------------------------
+# toTemplate($prefix, $suffix, \%named_params)
+#
+# Process the current node as a template.
+#------------------------------------------------------------------------
+
+sub toTemplate {
+    my $self = shift;
+    _template_node($self, $self->_args(@_));
+}
+
+
+#------------------------------------------------------------------------
+# childrenToTemplate($prefix, $suffix, \%named_params)
+#
+# Process all the current node's children as templates.
+#------------------------------------------------------------------------
+
+sub childrenToTemplate {
+    my $self = shift;
+    _template_kids($self, $self->_args(@_));
+}
+
+
+#------------------------------------------------------------------------
+# allChildrenToTemplate($prefix, $suffix, \%named_params)
+#
+# Process all the current node's children, and their children, and 
+# their children, etc., etc., as templates.  Same effect as calling the
+# childrenToTemplate() method with the 'deep' option set.
+#------------------------------------------------------------------------
+
+sub allChildrenToTemplate {
+    my $self = shift;
+    my $args = $self->_args(@_);
+    $args->{ deep } = 1;
+    _template_kids($self, $args);
+}
+
+
+#------------------------------------------------------------------------
+# _args($prefix, $suffix, \%name_params)
+#
+# Reads the optional positional parameters, $prefix and $suffix, and 
+# also examines any named parameters hash to construct a set of 
+# current configuration parameters.  Where not specified directly, the 
+# object defaults are used.
+#------------------------------------------------------------------------
+
+sub _args {
+    my $self = shift;
+    my $args = ref $_[-1] eq 'HASH' ? pop(@_) : { };
+    my $doc  = $self->getOwnerDocument() || $self;
+    my $data = $doc->[ XML::DOM::Node::_UserData ];
+
+    return {
+	prefix  => @_ ? shift : $args->{ prefix  } || $data->{ _PREFIX  },
+	suffix  => @_ ? shift : $args->{ suffix  } || $data->{ _SUFFIX  },
+	verbose =>              $args->{ verbose } || $data->{ _VERBOSE },
+	nospace =>              $args->{ nospace } || $data->{ _NOSPACE },
+	deep    =>              $args->{ deep    } || $data->{ _DEEP    },
+	default =>              $args->{ default } || $data->{ _DEFAULT },
+	context =>                                    $data->{ _CONTEXT },
+    };
+}
+
+
+
+#------------------------------------------------------------------------
+# _template_node($node, $args, $vars)
+#
+# Process a template for the current DOM node where the template name 
+# is taken from the node TagName, with any specified 'prefix' and/or 
+# 'suffix' applied.  The 'default' argument can also be provided to 
+# specify a default template to be used when a specific template can't
+# be found.  The $args parameter referenced a hash array through which
+# these configuration items are passed (see _args()).  The current DOM 
+# node is made available to the template as the variable 'node', along 
+# with any other variables passed in the optional $vars hash reference.
+# To permit the 'children' and 'prune' callbacks to be raised as node
+# methods (see _template_kids() below), these items, if defined in the
+# $vars hash, are copied into the node object where its AUTOLOAD method
+# can find them.
+#------------------------------------------------------------------------
+
+sub _template_node {
+    my $node = shift || die "no XML::DOM::Node reference\n";
+    my $args = shift || die "no XML::DOM args passed to _template_node\n";
+    my $vars = shift || { };
+    my $context = $args->{ context } || die "no context in XML::DOM args\n";
+    my $template;
+    my $output = '';
+
+    # if this is not an element then it is text so output it
+    unless ($node->getNodeType() == XML::DOM::ELEMENT_NODE ) {
+	if ($args->{ verbose }) {
+	    $output = $node->toString();
+	    $output =~ s/\s+$// if $args->{ nospace };
+	}
+    }
+    else {
+	my $element = ( $args->{ prefix  } || '' )
+	            .   $node->getTagName()
+                    . ( $args->{ suffix  } || '' );
+
+	# locate a template by name built from prefix, tagname and suffix
+	# or fall back on any default template specified
+	eval { $template = $context->template($element) };
+	eval { $template = $context->template($args->{ default }) }
+	    if $@ && $args->{ default };
+	$template = $element unless $template;
+
+	# copy 'children' and 'prune' callbacks into node object (see AUTOLOAD)
+	my $doc  = $node->getOwnerDocument() || $node;
+	my $data = $doc->[ XML::DOM::Node::_UserData ];
+
+	$data->{ _TT_CHILDREN } = $vars->{ children };
+	$data->{ _TT_PRUNE } = $vars->{ prune };
+
+	# add node reference to existing vars hash
+	$vars->{ node } = $node;
+	
+	$output = $context->include($template, $vars); 
+	
+	# break any circular references
+	delete $vars->{ node };
+	delete $data->{ _TT_CHILDREN };
+	delete $data->{ _TT_PRUNE };
+    }
+
+    return $output;
+}
+
+
+#------------------------------------------------------------------------
+# _template_kids($node, $args)
+#
+# Process all the children of the current node as templates, via calls 
+# to _template_node().  If the 'deep' argument is set, then the process
+# will continue recursively.  In this case, the node template is first 
+# processed, followed by any children of that node (i.e. depth first, 
+# parent before).  A closure called 'children' is created and added
+# to the Stash variables passed to _template_node().  This can be called 
+# from the parent template to process all child nodes at the current point.
+# This then "prunes" the tree preventing the children from being processed
+# after the parent template.  A 'prune' callback is also added to prune 
+# the tree without processing the children.  Note that _template_node()
+# copies these callbacks into each parent node, allowing them to be called
+# as [% node.
+#------------------------------------------------------------------------
+
+sub _template_kids {
+    my $node = shift || die "no XML::DOM::Node reference\n";
+    my $args = shift || die "no XML::DOM args passed to _template_kids\n";
+    my $context = $args->{ context } || die "no context in XML::DOM args\n";
+    my $output = '';
+
+    foreach my $kid ( $node->getChildNodes() ) {
+	# define some callbacks to allow template to call [% content %]
+	# or [% prune %].  They are also inserted into each node reference
+	# so they can be called as [% node.content %] and [% node.prune %]
+	my $prune = 0;
+	my $vars  = { };
+	$vars->{ children } = sub {
+	    $prune = 1;
+	    _template_kids($kid, $args);
+	};
+	$vars->{ prune } = sub {
+	    $prune = 1;
+	    return '';
+	};
+		
+	$output .= _template_node($kid, $args, $vars);
+	$output .= _template_kids($kid, $args)
+	    if $args->{ deep } && ! $prune;
+    }
+    return $output;
+}
+
+
+#========================================================================
+package XML::DOM::Element;
+#========================================================================
+
+use vars qw( $AUTOLOAD );
+
+sub AUTOLOAD {
+    my $self   = shift;
+    my $method = $AUTOLOAD;
+    my $attrib;
+
+    $method =~ s/.*:://;
+    return if $method eq 'DESTROY';
+
+    my $doc  = $self->getOwnerDocument() || $self;
+    my $data = $doc->[ XML::DOM::Node::_UserData ];
+
+    # call 'content' or 'prune' callbacks, if defined (see _template_node())
+    return &$attrib()
+	if ($method =~ /^children|prune$/)
+	    && defined($attrib = $data->{ "_TT_\U$method" })
+		&& ref $attrib eq 'CODE';
+
+    return $attrib
+	if defined ($attrib = $self->getAttribute($method));
+
+    return '';
+}
+
+
+1;
+
+__END__
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+#   This documentation is generated automatically from source
+#   templates.  Any changes you make here may be lost.
+# 
+#   The 'docsrc' documentation source bundle is available for download
+#   from http://www.template-toolkit.org/docs.html and contains all
+#   the source templates, XML files, scripts, etc., from which the
+#   documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Plugin::XML::DOM - Plugin interface to XML::DOM
+
+=head1 SYNOPSIS
+
+    # load plugin
+    [% USE dom = XML.DOM %]
+
+    # also provide XML::Parser options
+    [% USE dom = XML.DOM(ProtocolEncoding =E<gt> 'ISO-8859-1') %]
+
+    # parse an XML file
+    [% doc = dom.parse(filename) %]
+    [% doc = dom.parse(file => filename) %]
+
+    # parse XML text
+    [% doc = dom.parse(xmltext) %]
+    [% doc = dom.parse(text => xmltext) %]
+
+    # call any XML::DOM methods on document/element nodes
+    [% FOREACH node = doc.getElementsByTagName('report') %]
+       * [% node.getAttribute('title') %]     # or just '[% node.title %]'
+    [% END %]
+
+    # define VIEW to present node(s)
+    [% VIEW report notfound='xmlstring' %]
+       # handler block for a <report>...</report> element
+       [% BLOCK report %]
+          [% item.content(view) %]
+       [% END %]
+
+       # handler block for a <section title="...">...</section> element
+       [% BLOCK section %]
+       <h1>[% item.title %]</h1>
+       [% item.content(view) %]
+       [% END %]
+
+       # default template block converts item to string representation
+       [% BLOCK xmlstring; item.toString; END %]
+       
+       # block to generate simple text
+       [% BLOCK text; item; END %]
+    [% END %]
+
+    # now present node (and children) via view
+    [% report.print(node) %]
+
+    # or print node content via view
+    [% node.content(report) %]
+
+    # following methods are soon to be deprecated in favour of views
+    [% node.toTemplate %]
+    [% node.childrenToTemplate %]
+    [% node.allChildrenToTemplate %]
+
+=head1 PRE-REQUISITES
+
+This plugin requires that the XML::Parser (2.19 or later) and XML::DOM
+(1.27 or later) modules be installed.  These are available from CPAN:
+
+    http://www.cpan.org/modules/by-module/XML
+
+Note that the XML::DOM module is now distributed as part of the
+'libxml-enno' bundle.
+
+=head1 DESCRIPTION
+
+This is a Template Toolkit plugin interfacing to the XML::DOM module.
+The plugin loads the XML::DOM module and creates an XML::DOM::Parser
+object which is stored internally.  The parse() method can then be
+called on the plugin to parse an XML stream into a DOM document.
+
+    [% USE dom = XML.DOM %]
+    [% doc = dom.parse('/tmp/myxmlfile') %]
+
+NOTE: earlier versions of this XML::DOM plugin expected a filename to
+be passed as an argument to the constructor.  This is no longer
+supported due to the fact that it caused a serious memory leak.  We
+apologise for the inconvenience but must insist that you change your
+templates as shown:
+
+    # OLD STYLE: now fails with a warning
+    [% USE dom = XML.DOM('tmp/myxmlfile') %]
+
+    # NEW STYLE: do this instead
+    [% USE dom = XML.DOM %]
+    [% doc = dom.parse('tmp/myxmlfile') %]
+
+The root of the problem lies in XML::DOM creating massive circular
+references in the object models it constructs.  The dispose() method
+must be called on each document to release the memory that it would
+otherwise hold indefinately.  The XML::DOM plugin object (i.e. 'dom'
+in these examples) acts as a sentinel for the documents it creates
+('doc' and any others).  When the plugin object goes out of scope at
+the end of the current template, it will automatically call dispose()
+on any documents that it has created.  Note that if you dispose of the
+the plugin object before the end of the block (i.e.  by assigning a
+new value to the 'dom' variable) then the documents will also be
+disposed at that point and should not be used thereafter.
+
+    [% USE dom = XML.DOM %]
+    [% doc = dom.parse('/tmp/myfile') %]
+    [% dom = 'new value' %]     # releases XML.DOM plugin and calls
+                                # dispose() on 'doc', so don't use it!
+
+Any template processing parameters (see toTemplate() method and
+friends, below) can be specified with the constructor and will be used
+to define defaults for the object.
+
+    [% USE dom = XML.DOM(prefix => 'theme1/') %]
+
+The plugin constructor will also accept configuration options destined
+for the XML::Parser object:
+
+    [% USE dom = XML.DOM(ProtocolEncoding => 'ISO-8859-1') %]
+
+=head1 METHODS
+
+=head2 parse()
+
+The parse() method accepts a positional parameter which contains a filename
+or XML string.  It is assumed to be a filename unless it contains a E<lt>
+character.
+
+    [% xmlfile = '/tmp/foo.xml' %]
+    [% doc = dom.parse(xmlfile) %]
+
+    [% xmltext = BLOCK %]
+    <xml>
+      <blah><etc/></blah>
+      ...
+    </xml>
+    [% END %]
+    [% doc = dom.parse(xmltext) %]
+
+The named parameters 'file' (or 'filename') and 'text' (or 'xml') can also
+be used:
+
+    [% doc = dom.parse(file = xmlfile) %]
+    [% doc = dom.parse(text = xmltext) %]
+
+The parse() method returns an instance of the XML::DOM::Document object 
+representing the parsed document in DOM form.  You can then call any 
+XML::DOM methods on the document node and other nodes that its methods
+may return.  See L<XML::DOM> for full details.
+
+    [% FOREACH node = doc.getElementsByTagName('CODEBASE') %]
+       * [% node.getAttribute('href') %]
+    [% END %]
+
+This plugin also provides an AUTOLOAD method for XML::DOM::Node which 
+calls getAttribute() for any undefined methods.  Thus, you can use the 
+short form of 
+
+    [% node.attrib %]
+
+in place of
+
+    [% node.getAttribute('attrib') %]
+
+=head2 toTemplate()
+
+B<NOTE: This method will soon be deprecated in favour of the VIEW based
+approach desribed below.>
+
+This method will process a template for the current node on which it is 
+called.  The template name is constructed from the node TagName with any
+optional 'prefix' and/or 'suffix' options applied.  A 'default' template 
+can be named to be used when the specific template cannot be found.  The 
+node object is available to the template as the 'node' variable.
+
+Thus, for this XML fragment:
+
+    <page title="Hello World!">
+       ...
+    </page>
+
+and this template definition:
+
+    [% BLOCK page %]
+    Page: [% node.title %]
+    [% END %]
+
+the output of calling toTemplate() on the E<lt>pageE<gt> node would be:
+
+    Page: Hello World!
+
+=head2 childrenToTemplate()
+
+B<NOTE: This method will soon be deprecated in favour of the VIEW based
+approach desribed below.>
+
+Effectively calls toTemplate() for the current node and then for each of 
+the node's children.  By default, the parent template is processed first,
+followed by each of the children.  The 'children' closure can be called
+from within the parent template to have them processed and output 
+at that point.  This then suppresses the children from being processed
+after the parent template.
+
+Thus, for this XML fragment:
+
+    <foo>
+      <bar id="1"/>
+      <bar id="2"/>
+    </foo>
+
+and these template definitions:
+
+    [% BLOCK foo %]
+    start of foo
+    end of foo 
+    [% END %]
+
+    [% BLOCK bar %]
+    bar [% node.id %]
+    [% END %]
+
+the output of calling childrenToTemplate() on the parent E<lt>fooE<gt> node 
+would be:
+
+    start of foo
+    end of foo
+    bar 1
+    bar 2
+
+Adding a call to [% children %] in the 'foo' template:
+
+    [% BLOCK foo %]
+    start of foo
+    [% children %]
+    end of foo 
+    [% END %]
+
+then creates output as:
+
+    start of foo
+    bar 1 
+    bar 2
+    end of foo
+
+The 'children' closure can also be called as a method of the node, if you 
+prefer:
+
+    [% BLOCK foo %]
+    start of foo
+    [% node.children %]
+    end of foo 
+    [% END %]
+
+The 'prune' closure is also defined and can be called as [% prune %] or
+[% node.prune %].  It prunes the currrent node, preventing any descendants
+from being further processed.
+
+    [% BLOCK anynode %]
+    [% node.toString; node.prune %]
+    [% END %]
+
+=head2 allChildrenToTemplate()
+
+B<NOTE: This method will soon be deprecated in favour of the VIEW based
+approach desribed below.>
+
+Similar to childrenToTemplate() but processing all descendants (i.e. children
+of children and so on) recursively.  This is identical to calling the 
+childrenToTemplate() method with the 'deep' flag set to any true value.
+
+=head1 PRESENTING DOM NODES USING VIEWS
+
+You can define a VIEW to present all or part of a DOM tree by automatically
+mapping elements onto templates.  Consider a source document like the
+following:
+
+    <report>
+      <section title="Introduction">
+        <p>
+        Blah blah.
+        <ul>
+          <li>Item 1</li>
+          <li>item 2</li>
+        </ul>
+        </p>
+      </section>
+      <section title="The Gory Details">
+        ...
+      </section>
+    </report>
+
+We can load it up via the XML::DOM plugin and fetch the node for the 
+E<lt>reportE<gt> element.
+
+    [% USE dom = XML.DOM;
+       doc = dom.parse(file => filename);
+       report = doc.getElementsByTagName('report')
+    %]
+
+We can then define a VIEW as follows to present this document fragment in 
+a particular way.  The L<Template::Manual::Views> documentation
+contains further details on the VIEW directive and various configuration
+options it supports.
+
+    [% VIEW report_view notfound='xmlstring' %]
+       # handler block for a <report>...</report> element
+       [% BLOCK report %]
+          [% item.content(view) %]
+       [% END %]
+
+       # handler block for a <section title="...">...</section> element
+       [% BLOCK section %]
+       <h1>[% item.title %]</h1>
+       [% item.content(view) %]
+       [% END %]
+
+       # default template block converts item to string representation
+       [% BLOCK xmlstring; item.toString; END %]
+       
+       # block to generate simple text
+       [% BLOCK text; item; END %]
+    [% END %]
+
+Each BLOCK defined within the VIEW represents a presentation style for 
+a particular element or elements.  The current node is available via the
+'item' variable.  Elements that contain other content can generate it
+according to the current view by calling [% item.content(view) %].
+Elements that don't have a specific template defined are mapped to the
+'xmlstring' template via the 'notfound' parameter specified in the VIEW
+header.  This replicates the node as an XML string, effectively allowing
+general XML/XHTML markup to be passed through unmodified.
+
+To present the report node via the view, we simply call:
+
+    [% report_view.print(report) %]
+
+The output from the above example would look something like this:
+
+    <h1>Introduction</h1>
+    <p>
+    Blah blah.
+    <ul>
+      <li>Item 1</li>
+      <li>item 2</li>
+    </ul>
+    </p>
+  
+    <h1>The Gory Details</h1>
+    ...
+
+To print just the content of the report node (i.e. don't process the
+'report' template for the report node), you can call:
+
+    [% report.content(report_view) %]
+
+=head1 AUTHORS
+
+This plugin module was written by Andy Wardley E<lt>abw@xxxxxxxxxxxx<gt>
+and Simon Matthews E<lt>sam@xxxxxxxxxxxxxxxxxx<gt>.
+
+The XML::DOM module is by Enno Derksen E<lt>enno@xxxxxxxx<gt> and Clark 
+Cooper E<lt>coopercl@xxxxxxxxxxx<gt>.  It extends the the XML::Parser 
+module, also by Clark Cooper which itself is built on James Clark's expat
+library.
+
+=head1 VERSION
+
+2.6, distributed as part of the
+Template Toolkit version 2.14, released on 04 October 2004.
+
+
+
+=head1 HISTORY
+
+Version 2.5 : updated for use with version 1.27 of the XML::DOM module.
+
+=over 4
+
+=item *
+
+XML::DOM 1.27 now uses array references as the underlying data type
+for DOM nodes instead of hash array references.  User data is now
+bound to the _UserData node entry instead of being forced directly
+into the node hash.
+
+=back
+
+=head1 BUGS
+
+The childrenToTemplate() and allChildrenToTemplate() methods can easily
+slip into deep recursion.
+
+The 'verbose' and 'nospace' options are not documented.  They may 
+change in the near future.
+
+=head1 COPYRIGHT
+
+Copyright (C) 2000-2001 Andy Wardley, Simon Matthews.  All Rights Reserved.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 SEE ALSO
+
+L<Template::Plugin|Template::Plugin>, L<XML::DOM|XML::DOM>, L<XML::Parser|XML::Parser>
+

Added: www/trunk/XML/README
===================================================================
--- www/trunk/XML/README	                        (rev 0)
+++ www/trunk/XML/README	2007-04-01 11:07:38 UTC (rev 242)
@@ -0,0 +1,5 @@
+Unfortunately libtemplate-perl has removed XML plugin since 2.15.
+Here is backported files from 2.14 (and tweaked a bit) for keeping
+a compatibility.
+Please copy these files to your /usr/lib/perl5/Template/Plugin/XML/
+directory until the upstream author revives XML plugin.

Added: www/trunk/XML/RSS.pm
===================================================================
--- www/trunk/XML/RSS.pm	                        (rev 0)
+++ www/trunk/XML/RSS.pm	2007-04-01 11:07:38 UTC (rev 242)
@@ -0,0 +1,194 @@
+#============================================================= -*-Perl-*-
+#
+# Template::Plugin::XML::RSS
+#
+# DESCRIPTION
+#
+#   Template Toolkit plugin which interfaces to Jonathan Eisenzopf's XML::RSS
+#   module.  RSS is the Rich Site Summary format.
+#
+# AUTHOR
+#   Andy Wardley   <abw@xxxxxxx>
+#
+# COPYRIGHT
+#   Copyright (C) 2000 Andy Wardley.  All Rights Reserved.
+#
+#   This module is free software; you can redistribute it and/or
+#   modify it under the same terms as Perl itself.
+#
+#----------------------------------------------------------------------------
+#
+# $Id: RSS.pm,v 2.65 2004/01/30 19:33:36 abw Exp $
+#
+#============================================================================
+
+package Template::Plugin::XML::RSS;
+
+require 5.004;
+
+use strict;
+use vars qw( $VERSION );
+use base qw( Template::Plugin );
+use Template::Plugin;
+use XML::RSS;
+
+$VERSION = sprintf("%d.%02d", q$Revision: 2.65 $ =~ /(\d+)\.(\d+)/);
+
+sub load {
+    return $_[0];
+}
+
+sub new {
+    my ($class, $context, $filename) = @_;
+
+    return $class->fail('No filename specified')
+	unless $filename;
+    
+    my $rss = XML::RSS->new
+	or return $class->fail('failed to create XML::RSS');
+
+    # Attempt to determine if $filename is an XML string or
+    # a filename.  Based on code from the XML.XPath plugin.
+    eval {
+        if ($filename =~ /\</) {
+	    $rss->parse($filename);
+        }
+        else {
+	    $rss->parsefile($filename)
+        }
+    } and not $@
+	or return $class->error("failed to parse $filename: $@");
+
+    return $rss;
+}
+
+1;
+
+__END__
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+#   This documentation is generated automatically from source
+#   templates.  Any changes you make here may be lost.
+# 
+#   The 'docsrc' documentation source bundle is available for download
+#   from http://www.template-toolkit.org/docs.html and contains all
+#   the source templates, XML files, scripts, etc., from which the
+#   documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Plugin::XML::RSS - Plugin interface to XML::RSS
+
+=head1 SYNOPSIS
+
+    [% USE news = XML.RSS($filename) %]
+   
+    [% FOREACH item = news.items %]
+       [% item.title %]
+       [% item.link  %]
+    [% END %]
+
+=head1 PRE-REQUISITES
+
+This plugin requires that the XML::Parser and XML::RSS modules be 
+installed.  These are available from CPAN:
+
+    http://www.cpan.org/modules/by-module/XML
+
+=head1 DESCRIPTION
+
+This Template Toolkit plugin provides a simple interface to the
+XML::RSS module.
+
+    [% USE news = XML.RSS('mysite.rdf') %]
+
+It creates an XML::RSS object, which is then used to parse the RSS
+file specified as a parameter in the USE directive.  A reference to
+the XML::RSS object is then returned.
+
+An RSS (Rich Site Summary) file is typically used to store short news
+'headlines' describing different links within a site.  This example is
+extracted from http://slashdot.org/slashdot.rdf.
+
+    <?xml version="1.0"?><rdf:RDF
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+    xmlns="http://my.netscape.com/rdf/simple/0.9/";>
+    
+      <channel>
+    	<title>Slashdot:News for Nerds. Stuff that Matters.</title>
+    	<link>http://slashdot.org</link>
+    	<description>News for Nerds.  Stuff that Matters</description>
+      </channel>
+    
+      <image>
+    	<title>Slashdot</title>
+    	<url>http://slashdot.org/images/slashdotlg.gif</url>
+    	<link>http://slashdot.org</link>
+      </image>
+      
+      <item>
+    	<title>DVD CCA Battle Continues Next Week</title>
+    	<link>http://slashdot.org/article.pl?sid=00/01/12/2051208</link>
+      </item>
+      
+      <item>
+    	<title>Matrox to fund DRI Development</title>
+    	<link>http://slashdot.org/article.pl?sid=00/01/13/0718219</link>
+      </item>
+      
+      <item>
+    	<title>Mike Shaver Leaving Netscape</title>
+    	<link>http://slashdot.org/article.pl?sid=00/01/13/0711258</link>
+      </item>
+      
+    </rdf:RDF>
+
+The attributes of the channel and image elements can be retrieved directly
+from the plugin object using the familiar dotted compound notation:
+
+    [% news.channel.title  %]
+    [% news.channel.link   %]
+    [% news.channel.etc... %]  
+
+    [% news.image.title    %]
+    [% news.image.url      %]
+    [% news.image.link     %]
+    [% news.image.etc...   %]  
+
+The list of news items can be retrieved using the 'items' method:
+
+    [% FOREACH item = news.items %]
+       [% item.title %]
+       [% item.link  %]
+    [% END %]
+
+=head1 AUTHORS
+
+This plugin was written by Andy Wardley E<lt>abw@xxxxxxxxxxxx<gt>,
+inspired by an article in Web Techniques by Randal Schwartz
+E<lt>merlyn@xxxxxxxxxxxxxxx<gt>.
+
+The XML::RSS module, which implements all of the functionality that
+this plugin delegates to, was written by Jonathan Eisenzopf 
+E<lt>eisen@xxxxxxxxxx<gt>.
+
+=head1 VERSION
+
+2.65, distributed as part of the
+Template Toolkit version 2.14, released on 04 October 2004.
+
+=head1 COPYRIGHT
+
+  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
+  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 SEE ALSO
+
+L<Template::Plugin|Template::Plugin>, L<XML::RSS|XML::RSS>, L<XML::Parser|XML::Parser>
+

Added: www/trunk/XML/Simple.pm
===================================================================
--- www/trunk/XML/Simple.pm	                        (rev 0)
+++ www/trunk/XML/Simple.pm	2007-04-01 11:07:38 UTC (rev 242)
@@ -0,0 +1,142 @@
+#============================================================= -*-Perl-*-
+#
+# Template::Plugin::XML::Simple
+#
+# DESCRIPTION
+#   Template Toolkit plugin interfacing to the XML::Simple.pm module.
+#
+# AUTHOR
+#   Andy Wardley   <abw@xxxxxxx>
+#
+# COPYRIGHT
+#   Copyright (C) 2001 Andy Wardley.  All Rights Reserved.
+#
+#   This module is free software; you can redistribute it and/or
+#   modify it under the same terms as Perl itself.
+#
+#----------------------------------------------------------------------------
+#
+# $Id: Simple.pm,v 2.65 2004/09/24 06:49:13 abw Exp $
+#
+#============================================================================
+
+package Template::Plugin::XML::Simple;
+
+require 5.004;
+
+use strict;
+use Template::Plugin;
+use XML::Simple;
+
+use base qw( Template::Plugin );
+use vars qw( $VERSION );
+
+$VERSION = sprintf("%d.%02d", q$Revision: 2.65 $ =~ /(\d+)\.(\d+)/);
+
+
+#------------------------------------------------------------------------
+# new($context, $file_or_text, \%config)
+#------------------------------------------------------------------------
+
+sub new {
+    my $class   = shift;
+    my $context = shift;
+    my $input   = shift;
+    my $args    = ref $_[-1] eq 'HASH' ? pop(@_) : { };
+
+    if (defined($input)) {  
+        # an input parameter can been be provided and can contain 
+        # XML text or the filename of an XML file, which we load
+        # using insert() to honour the INCLUDE_PATH; then we feed 
+        # it into XMLin().
+        $input = $context->insert($input) unless ( $input =~ /</ );
+        return XMLin($input, %$args);
+    } 
+    else {
+        # otherwise return a XML::Simple object
+        return new XML::Simple;
+    }
+}
+
+
+
+#------------------------------------------------------------------------
+# _throw($errmsg)
+#
+# Raise a Template::Exception of type XML.Simple via die().
+#------------------------------------------------------------------------
+
+sub _throw {
+    my ($self, $error) = @_;
+    die (Template::Exception->new('XML.Simple', $error));
+}
+
+
+1;
+
+__END__
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+#   This documentation is generated automatically from source
+#   templates.  Any changes you make here may be lost.
+# 
+#   The 'docsrc' documentation source bundle is available for download
+#   from http://www.template-toolkit.org/docs.html and contains all
+#   the source templates, XML files, scripts, etc., from which the
+#   documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Plugin::XML::Simple - Plugin interface to XML::Simple
+
+=head1 SYNOPSIS
+
+    # load plugin and specify XML text or file to parse
+    [% USE xml = XML.Simple(xml_file_or_text) %]
+
+    # or load plugin as an object...
+    [% USE xml = XML.Simple %]
+
+    # ...then use XMLin or XMLout as usual
+    [% xml.XMLout(data_ref, args) %]
+    [% xml.XMLin(xml_file_or_text, args) %]
+
+=head1 DESCRIPTION
+
+This is a Template Toolkit plugin interfacing to the XML::Simple module.
+
+=head1 PRE-REQUISITES
+
+This plugin requires that the XML::Parser and XML::Simple modules be 
+installed.  These are available from CPAN:
+
+    http://www.cpan.org/modules/by-module/XML
+
+=head1 AUTHORS
+
+This plugin wrapper module was written by Andy Wardley
+E<lt>abw@xxxxxxxxxxxx<gt>.
+
+The XML::Simple module which implements all the core functionality 
+was written by Grant McLean E<lt>grantm@xxxxxxxxxx<gt>.
+
+=head1 VERSION
+
+2.65, distributed as part of the
+Template Toolkit version 2.14, released on 04 October 2004.
+
+=head1 COPYRIGHT
+
+  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
+  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 SEE ALSO
+
+L<Template::Plugin|Template::Plugin>, L<XML::Simple|XML::Simple>, L<XML::Parser|XML::Parser>
+

Added: www/trunk/XML/Style.pm
===================================================================
--- www/trunk/XML/Style.pm	                        (rev 0)
+++ www/trunk/XML/Style.pm	2007-04-01 11:07:38 UTC (rev 242)
@@ -0,0 +1,357 @@
+#============================================================= -*-Perl-*-
+#
+# Template::Plugin::XML::Style
+#
+# DESCRIPTION
+#   Template Toolkit plugin which performs some basic munging of XML 
+#   to perform simple stylesheet like transformations.
+#
+# AUTHOR
+#   Andy Wardley   <abw@xxxxxxx>
+#
+# COPYRIGHT
+#   Copyright (C) 2001 Andy Wardley.  All Rights Reserved.
+#
+#   This module is free software; you can redistribute it and/or
+#   modify it under the same terms as Perl itself.
+#
+# REVISION
+#   $Id: Style.pm,v 2.35 2004/01/30 19:33:36 abw Exp $
+#
+#============================================================================
+
+package Template::Plugin::XML::Style;
+
+require 5.004;
+
+use strict;
+use Template::Plugin::Filter;
+
+use base qw( Template::Plugin::Filter );
+use vars qw( $VERSION $DYNAMIC $FILTER_NAME );
+
+$VERSION = sprintf("%d.%02d", q$Revision: 2.35 $ =~ /(\d+)\.(\d+)/);
+$DYNAMIC = 1;
+$FILTER_NAME = 'xmlstyle';
+
+
+#------------------------------------------------------------------------
+# new($context, \%config)
+#------------------------------------------------------------------------
+
+sub init {
+    my $self = shift;
+    my $name = $self->{ _ARGS }->[0] || $FILTER_NAME;
+    $self->install_filter($name);
+    return $self;
+}
+
+
+sub filter {
+    my ($self, $text, $args, $config) = @_;
+
+    # munge start tags
+    $text =~ s/ < ([\w\.\:]+) ( \s+ [^>]+ )? > 
+	      / $self->start_tag($1, $2, $config)
+	      /gsex;
+
+    # munge end tags
+    $text =~ s/ < \/ ([\w\.\:]+) > 
+	      / $self->end_tag($1, $config)
+	      /gsex;
+
+    return $text;
+
+}
+
+
+sub start_tag {
+    my ($self, $elem, $textattr, $config) = @_;
+    $textattr ||= '';
+    my ($pre, $post);
+
+    # look for an element match in the stylesheet
+    my $match = $config->{ $elem } 
+	|| $self->{ _CONFIG }->{ $elem }
+	    || return "<$elem$textattr>";
+	
+    # merge element attributes into copy of stylesheet attributes
+    my $attr = { %{ $match->{ attributes } || { } } };
+    while ($textattr =~ / \s* ([\w\.\:]+) = " ([^"]+) " /gsx ) {
+	$attr->{ $1 } = $2;
+    }
+    $textattr = join(' ', map { "$_=\"$attr->{$_}\"" } keys %$attr);
+    $textattr = " $textattr" if $textattr;
+
+    $elem = $match->{ element    } || $elem;
+    $pre  = $match->{ pre_start  } || '';
+    $post = $match->{ post_start } || '';
+
+    return "$pre<$elem$textattr>$post";
+}
+
+
+sub end_tag {
+    my ($self, $elem, $config) = @_;
+    my ($pre, $post);
+
+    # look for an element match in the stylesheet
+    my $match = $config->{ $elem } 
+	|| $self->{ _CONFIG }->{ $elem }
+	|| return "</$elem>";
+	
+    $elem = $match->{ element  } || $elem;
+    $pre  = $match->{ pre_end  } || '';
+    $post = $match->{ post_end } || '';
+    
+    return "$pre</$elem>$post";
+}
+
+
+1;
+
+__END__
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+#   This documentation is generated automatically from source
+#   templates.  Any changes you make here may be lost.
+# 
+#   The 'docsrc' documentation source bundle is available for download
+#   from http://www.template-toolkit.org/docs.html and contains all
+#   the source templates, XML files, scripts, etc., from which the
+#   documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Plugin::XML::Style - Simple XML stylesheet transfomations
+
+=head1 SYNOPSIS
+
+    [% USE xmlstyle 
+           table = { 
+               attributes = { 
+                   border      = 0
+                   cellpadding = 4
+                   cellspacing = 1
+               }
+           }
+    %]
+
+    [% FILTER xmlstyle %]
+    <table>
+    <tr>
+      <td>Foo</td> <td>Bar</td> <td>Baz</td>
+    </tr>
+    </table>
+    [% END %]
+
+=head1 DESCRIPTION
+
+This plugin defines a filter for performing simple stylesheet based 
+transformations of XML text.  
+
+Named parameters are used to define those XML elements which require
+transformation.  These may be specified with the USE directive when
+the plugin is loaded and/or with the FILTER directive when the plugin
+is used.
+
+This example shows how the default attributes C<border="0"> and
+C<cellpadding="4"> can be added to E<lt>tableE<gt> elements.
+
+    [% USE xmlstyle 
+           table = { 
+               attributes = { 
+                   border      = 0
+                   cellpadding = 4
+               }
+           }
+    %]
+
+    [% FILTER xmlstyle %]
+    <table>
+       ...
+    </table>
+    [% END %]
+
+This produces the output:
+
+    <table border="0" cellpadding="4">
+       ...
+    </table>
+
+Parameters specified within the USE directive are applied automatically each
+time the C<xmlstyle> FILTER is used.  Additional parameters passed to the 
+FILTER directive apply for only that block.
+
+    [% USE xmlstyle 
+           table = { 
+               attributes = { 
+                   border      = 0
+                   cellpadding = 4
+               }
+           }
+    %]
+
+    [% FILTER xmlstyle
+           tr = {
+               attributes = {
+                   valign="top"
+               }
+           }
+    %]
+    <table>
+       <tr>
+         ...
+       </tr>
+    </table>
+    [% END %]
+
+Of course, you may prefer to define your stylesheet structures once and 
+simply reference them by name.  Passing a hash reference of named parameters
+is just the same as specifying the named parameters as far as the Template 
+Toolkit is concerned.
+
+    [% style_one = {
+          table = { ... }
+          tr    = { ... }
+       }
+       style_two = {
+          table = { ... }
+          td    = { ... }
+       }
+       style_three = {
+          th = { ... }
+          tv = { ... }
+       }
+    %]
+
+    [% USE xmlstyle style_one %]
+
+    [% FILTER xmlstyle style_two %]
+       # style_one and style_two applied here 
+    [% END %]
+      
+    [% FILTER xmlstyle style_three %]
+       # style_one and style_three applied here 
+    [% END %]
+
+Any attributes defined within the source tags will override those specified
+in the style sheet.
+
+    [% USE xmlstyle 
+           div = { attributes = { align = 'left' } } 
+    %]
+
+
+    [% FILTER xmlstyle %]
+    <div>foo</div>
+    <div align="right">bar</div>
+    [% END %]
+
+The output produced is:
+
+    <div align="left">foo</div>
+    <div align="right">bar</div>
+
+The filter can also be used to change the element from one type to another.
+
+    [% FILTER xmlstyle 
+              th = { 
+                  element = 'td'
+                  attributes = { bgcolor='red' }
+              }
+    %]
+    <tr>
+      <th>Heading</th>
+    </tr>
+    <tr>
+      <td>Value</td>
+    </tr>
+    [% END %]
+
+The output here is as follows.  Notice how the end tag C<E<lt>/thE<gt>> is
+changed to C<E<lt>/tdE<gt>> as well as the start tag.
+
+    <tr>
+      <td bgcolor="red">Heading</td>
+    </tr>
+    <tr>
+      <td>Value</td>
+    </tr>
+
+You can also define text to be added immediately before or after the 
+start or end tags.  For example:
+
+    [% FILTER xmlstyle 
+              table = {
+                  pre_start = '<div align="center">'
+                  post_end  = '</div>'
+              }
+              th = { 
+                  element    = 'td'
+                  attributes = { bgcolor='red' }
+                  post_start = '<b>'
+                  pre_end    = '</b>'
+              }
+    %]
+    <table>
+    <tr>
+      <th>Heading</th>
+    </tr>
+    <tr>
+      <td>Value</td>
+    </tr>
+    </table>
+    [% END %]
+
+The output produced is:
+
+    <div align="center">
+    <table>
+    <tr>
+      <td bgcolor="red"><b>Heading</b></td>
+    </tr>
+    <tr>
+      <td>Value</td>
+    </tr>
+    </table>
+    </div>
+
+=head1 AUTHOR
+
+Andy Wardley E<lt>abw@xxxxxxxxxxxxxxxx<gt>
+
+L<http://www.andywardley.com/|http://www.andywardley.com/>
+
+
+
+
+=head1 VERSION
+
+2.35, distributed as part of the
+Template Toolkit version 2.14, released on 04 October 2004.
+
+=head1 COPYRIGHT
+
+  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
+  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 SEE ALSO
+
+L<Template::Plugin|Template::Plugin>
+
+=cut
+
+# Local Variables:
+# mode: perl
+# perl-indent-level: 4
+# indent-tabs-mode: nil
+# End:
+#
+# vim: expandtab shiftwidth=4:

Added: www/trunk/XML/XPath.pm
===================================================================
--- www/trunk/XML/XPath.pm	                        (rev 0)
+++ www/trunk/XML/XPath.pm	2007-04-01 11:07:38 UTC (rev 242)
@@ -0,0 +1,284 @@
+#============================================================= -*-Perl-*-
+#
+# Template::Plugin::XML::XPath
+#
+# DESCRIPTION
+#
+#   Template Toolkit plugin interfacing to the XML::XPath.pm module.
+#
+# AUTHOR
+#   Andy Wardley   <abw@xxxxxxx>
+#
+# COPYRIGHT
+#   Copyright (C) 2000 Andy Wardley.  All Rights Reserved.
+#
+#   This module is free software; you can redistribute it and/or
+#   modify it under the same terms as Perl itself.
+#
+#----------------------------------------------------------------------------
+#
+# $Id: XPath.pm,v 2.70 2004/01/30 19:33:36 abw Exp $
+#
+#============================================================================
+
+package Template::Plugin::XML::XPath;
+
+require 5.004;
+
+use strict;
+use Template::Exception;
+use Template::Plugin;
+use XML::XPath;
+
+use base qw( Template::Plugin );
+use vars qw( $VERSION );
+
+$VERSION = sprintf("%d.%02d", q$Revision: 2.70 $ =~ /(\d+)\.(\d+)/);
+
+
+#------------------------------------------------------------------------
+# new($context, \%config)
+#
+# Constructor method for XML::XPath plugin.  Creates an XML::XPath
+# object and initialises plugin configuration.
+#------------------------------------------------------------------------
+
+sub new {
+    my $class   = shift;
+    my $context = shift;
+    my $args    = ref $_[-1] eq 'HASH' ? pop(@_) : { };
+    my ($content, $about);
+
+    # determine the input source from a positional parameter (may be a 
+    # filename or XML text if it contains a '<' character) or by using
+    # named parameters which may specify one of 'file', 'filename', 'text'
+    # or 'xml'
+
+    if ($content = shift) {
+	if ($content =~ /\</) {
+	    $about = 'xml text';
+	    $args->{ xml } = $content;
+	}
+	else {
+	    $about = "xml file $content";
+	    $args->{ filename } = $content;
+	}
+    }
+    elsif ($content = $args->{ text } || $args->{ xml }) {
+	$about = 'xml text';
+	$args->{ xml } = $content;
+    }
+    elsif ($content = $args->{ file } || $args->{ filename }) {
+	$about = "xml file $content";
+	$args->{ filename } = $content;
+    }
+    else {
+	return $class->_throw('no filename or xml text specified');
+    }
+    
+    return XML::XPath->new(%$args)
+	or $class->_throw("failed to create XML::XPath::Parser\n");
+}
+
+
+
+#------------------------------------------------------------------------
+# _throw($errmsg)
+#
+# Raise a Template::Exception of type XML.XPath via die().
+#------------------------------------------------------------------------
+
+sub _throw {
+    my ($self, $error) = @_;
+#    print STDERR "about to throw $error\n";
+    die (Template::Exception->new('XML.XPath', $error));
+}
+
+
+#========================================================================
+package XML::XPath::Node::Element;
+#========================================================================
+
+#------------------------------------------------------------------------
+# present($view)
+#
+# Method to present an element node via a view.
+#------------------------------------------------------------------------
+
+sub present {
+    my ($self, $view) = @_;
+    $view->view($self->getName(), $self);
+}
+
+sub content {
+    my ($self, $view) = @_;
+    my $output = '';
+    foreach my $node (@{ $self->getChildNodes }) {
+	$output .= $node->present($view);
+    }
+    return $output;
+}
+
+#----------------------------------------------------------------------
+# starttag(), endtag()
+#
+# Methods to output the start & end tag, e.g. <foo bar="baz"> & </foo>
+#----------------------------------------------------------------------
+
+sub starttag {
+    my ($self) = @_;
+    my $output =  "<". $self->getName();
+    foreach my $attr ($self->getAttributes())
+    {
+	$output .= $attr->toString();
+    }
+    $output .= ">";
+    return $output;
+}
+
+sub endtag {
+    my ($self) = @_;
+    return "</". $self->getName() . ">";
+}
+
+#========================================================================
+package XML::XPath::Node::Text;
+#========================================================================
+
+#------------------------------------------------------------------------
+# present($view)
+#
+# Method to present a text node via a view.
+#------------------------------------------------------------------------
+
+sub present {
+    my ($self, $view) = @_;
+    $view->view('text', $self->string_value);
+}
+
+
+#========================================================================
+package XML::XPath::Node::Comment;
+#========================================================================
+
+sub present  { return ''; }
+sub starttag { return ''; }
+sub endtag   { return ''; }
+
+
+1;
+
+__END__
+
+
+#------------------------------------------------------------------------
+# IMPORTANT NOTE
+#   This documentation is generated automatically from source
+#   templates.  Any changes you make here may be lost.
+# 
+#   The 'docsrc' documentation source bundle is available for download
+#   from http://www.template-toolkit.org/docs.html and contains all
+#   the source templates, XML files, scripts, etc., from which the
+#   documentation for the Template Toolkit is built.
+#------------------------------------------------------------------------
+
+=head1 NAME
+
+Template::Plugin::XML::XPath - Plugin interface to XML::XPath
+
+=head1 SYNOPSIS
+
+    # load plugin and specify XML file to parse
+    [% USE xpath = XML.XPath(xmlfile) %]
+    [% USE xpath = XML.XPath(file => xmlfile) %]
+    [% USE xpath = XML.XPath(filename => xmlfile) %]
+
+    # load plugin and specify XML text to parse
+    [% USE xpath = XML.XPath(xmltext) %]
+    [% USE xpath = XML.XPath(xml => xmltext) %]
+    [% USE xpath = XML.XPath(text => xmltext) %]
+
+    # then call any XPath methods (see XML::XPath docs)
+    [% FOREACH page = xpath.findnodes('/html/body/page') %]
+       [% page.getAttribute('title') %]
+    [% END %]
+
+    # define VIEW to present node(s)
+    [% VIEW repview notfound='xmlstring' %]
+       # handler block for a <report>...</report> element
+       [% BLOCK report %]
+          [% item.content(view) %]
+       [% END %]
+
+       # handler block for a <section title="...">...</section> element
+       [% BLOCK section %]
+       <h1>[% item.getAttribute('title') | html %]</h1>
+       [% item.content(view) %]
+       [% END %]
+
+       # default template block passes tags through and renders
+       # out the children recursivly
+       [% BLOCK xmlstring; 
+          item.starttag; item.content(view); item.endtag;
+       END %]
+       
+       # block to generate simple text
+       [% BLOCK text; item | html; END %]
+    [% END %]
+
+    # now present node (and children) via view
+    [% repview.print(page) %]
+
+    # or print node content via view
+    [% page.content(repview) %]
+
+=head1 PRE-REQUISITES
+
+This plugin requires that the XML::Parser and XML::XPath modules be 
+installed.  These are available from CPAN:
+
+    http://www.cpan.org/modules/by-module/XML
+
+=head1 DESCRIPTION
+
+This is a Template Toolkit plugin interfacing to the XML::XPath module.
+
+All methods implemented by the XML::XPath modules are available.  In
+addition, the XML::XPath::Node::Element module implements
+present($view) and content($view) methods method for seamless
+integration with Template Toolkit VIEWs.  The XML::XPath::Node::Text
+module is also adorned with a present($view) method which presents
+itself via the view using the 'text' template.
+
+To aid the reconstruction of XML, methods starttag and endtag are
+added to XML::XPath::Node::Element which return the start and
+end tag for that element.  This means that you can easily do:
+
+  [% item.starttag %][% item.content(view) %][% item.endtag %]
+
+To render out the start tag, followed by the content rendered in the
+view "view", followed by the end tag.
+
+=head1 AUTHORS
+
+This plugin module was written by Andy Wardley E<lt>abw@xxxxxxxxxxxx<gt>.
+
+The XML::XPath module is by Matt Sergeant E<lt>matt@xxxxxxxxxxxxx<gt>.
+
+=head1 VERSION
+
+2.70, distributed as part of the
+Template Toolkit version 2.14, released on 04 October 2004.
+
+=head1 COPYRIGHT
+
+  Copyright (C) 1996-2004 Andy Wardley.  All Rights Reserved.
+  Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.
+
+This module is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 SEE ALSO
+
+L<Template::Plugin|Template::Plugin>, L<XML::XPath|XML::XPath>, L<XML::Parser|XML::Parser>
+