0.07 Wed Jan 27 1999
- Speed improvements. Now faster than XML::XQL (DOM) for all cases
- Some minor bug fixes
- Fixes to Stream mode - see README - needs to patch XML::Parser version
2.19
====================================================================
*** WARNING *** WARNING *** WARNING *** WARNING ***
This module requires XML::Parser version 2.20, but that's not been released
yet. To get around this you need to make 2 patches to XML::Parser (1 of them
is non-essential). First, the non-essential bug fix:
In XML::Parser, the Stream style has a function doText which looks like:
sub doText {
...
if ($_) {
...
}
}
change that to:
sub doText {
...
if (defined $_) {
...
}
}
And the other, required fix is to add the following function to Expat.pm:
sub finish {
my ($self) = @_;
foreach (keys %{$self->{_Setters}}) {
&{$self->{_Setters}->{$_}}($self->{Parser}, undef);
}
}
The first patch fixes a bug where you have 0 and the finish function
allows you to break out of a parse phase.
END OF WARNING.
====================================================================
NAME
CGI::XMLForm - Extension of CGI.pm which reads/generates
formated XML.
This is currently alpha software, and I'm looking for feedback.
Note though that it is proving quite stable in our mod_perl
environment, so it is ready for production use.
NB: This is a subclass of CGI.pm, so can be used in it's place.
SYNOPSIS
use CGI::XMLForm;
my $cgi = new CGI::XMLForm;
if ($cgi->param) {
print $cgi->header, $cgi->pre($cgi->escapeHTML($cgi->toXML));
}
else {
open(FILE, "test.xml") or die "Can't open: $!";
my @queries = ('/a', '/a/b*', '/a/b/c*', /a/d');
print $cgi->header,
$cgi->pre($cgi->escapeHTML(
join "\n", $cgi->readXML(*FILE, @queries)));
}
DESCRIPTION
This module can either create form field values from XML based
on XQL style queries (full XQL is _not_ supported - this module
is designed for speed), or it can create XML from form values.
There are 2 key functions: toXML and readXML.
toXML
The module takes form fields given in a specialised format, and
outputs them to XML based on that format. The idea is that you
can create forms that define the resulting XML at the back end.
The format for the form elements is:
which creates the following XML:

Entered Value

It's the user's responsibility to design appropriate forms to
make use of this module, although coming later will be a small
module that uses my XML::DTDParser to create all the form
elements given a DTD.
Also supported are attribute form items, that allow creation of
element attributes. The syntax for this is:
Which creates the following XML:

Also possible are relative paths. So the following form
elements:
Will create the following XML:

value1

value2

value3

SYNTAX
The following is a brief syntax guideline
Full paths start with a "/" :
"/table/tr/td"
Relative paths start with either ".." or just a tag name.
"../tr/td"
"td"
Relative paths go at the level above the previous path, unless
the previous path was also a relative path, in which case it
goes at the same level. This seems confusing at first (you might
expect it to always go at the level above the previous element),
but it makes your form easier to design. Take the following
example: You have a timesheet (see the example supplied in the
archive) that has monday,tuesday,etc. Our form can look like
this:
...
Rather than:
...
If unsure I recommend using full paths, relative paths are great
for repeating groups of data, but weak for heavily structured
data. Picture the following paths:
/timesheet/employee/name/forename
../surname
title
../department
This actually creates the following XML:
val1
val2val3>val4
Confusing eh? Far better to say:
/timesheet/employee/name/forename
/timesheet/employee/name/surname
/timesheet/employee/name/title
/timesheet/employee/department
Or alternatively, better still:
/timesheet/employee/name (Make hidden and no value)
forename
surname
title
../department
Attributes go in square brackets. Attribute names are preceded
with an "@", and attribute values follow an "=" sign and are
enclosed in quotes. Multiple attributes are separated with " and
".
/table[@bgcolor="blue" and @width="100%"]/tr/td
If setting an attribute, it follows after the tag that it is
associated with, after a "/" and it's name is preceded with an
"@".
/table/@bgcolor
readXML
readXML takes either a file handle or text as the first
parameter and a list of queries following that. The XML is
searched for the queries and it returns a list of tuples that
are the query and the match.
It's easier to demonstrate this with an example. Given the
following XML:
Foo
Bar
FredBlogsRed
BarbaraCartlandFood
And the following queries:
/a
/a/b*
c*
/a/d
it returns the following result as a list:
/a
Foo
/a/b
Bar
c
Fred
c
Blogs
/a/b
Red
c
Barbara
c
Cartland
/a/d
Food
(NB: This is slightly incorrect - for /a and /a/b it will return
"Foo\n " and "Bar\n " respectively).
The queries support relative paths like toXML (including parent
paths), and they also support wildcards using ".*" or ".*?"
(preferably ".*?" as it's probably a better match). If a
wildcard is specified the results will have the actual value
substituted with the wildcard. Wildcards are a bit experimental,
so be careful ;-)
Caveats
There are a few caveats to using this module:
AUTHOR
Matt Sergeant msergeant@ndirect.co.uk,
sergeant@geocities.com
Based on an original concept, and discussions with, Jonathan
Eisenzopf. Thanks to the Perl-XML mailing list for
suggesting the XSL syntax.
Special thanks to Francois Belanger (francois@sitepak.com)
for his mentoring and help with the syntax design.
SEE ALSO
CGI(1), CGI::XML