PerlData(3pm)
β¨ NAME β¨
XML::Generator::PerlData β the Perl extension for generating SAX2 events from nested Perl data structures π (yes, it's PerlData(3pm), the user-contributed perl documentation, and yes she's iconic)
πΈ SYNOPSIS πΈ
use XML::Generator::PerlData;
use SomeSAX2HandlerOrFilter;
## Simple style ##
# get a deeply nested Perl data structure...
my $hash_ref = $obj->getScaryNestedDataStructure();
# create an instance of a handler class to forward events to...
my $handler = SomeSAX2HandlerOrFilter->new();
# create an instance of the PerlData driver...
my $driver = XML::Generator::PerlData->new( Handler => $handler );
# generate XML from the data structure...
$driver->parse( $hash_ref );
## Or, Stream style ##
use XML::Generator::PerlData;
use SomeSAX2HandlerOrFilter;
# create an instance of a handler class to forward events to...
my $handler = SomeSAX2HandlerOrFilter->new();
# create an instance of the PerlData driver...
my $driver = XML::Generator::PerlData->new( Handler => $handler );
# start the event stream...
$driver->parse_start();
# pass the data through in chunks
# (from a database handle here)
while ( my $array_ref = $dbd_sth->fetchrow_arrayref ) {
$driver->parse_chunk( $array_ref );
}
# end the event stream...
$driver->parse_end();
and you're done... periodt π
π DESCRIPTION π
XML::Generator::PerlData is literally the easiest way to generate SAX2 events from nested Perl data structures, while also handing you finer-grained control over the resulting document streams. Obsessed.
Processing comes in two flavors: Simple Style and Stream Style:
In a nutshell (and bestie, I mean a nutshell), 'simple style' is best when you have one single Perl data structure and you just want it converted to XML as fast and painlessly as possible. 'stream style' is the move when you're receiving chunks of data β like, say, from a DBI handle β and you want to process those chunks as they show up. Head to PROCESSING METHODS for the full tea on how each style works π«
π CONSTRUCTOR METHOD AND CONFIGURATION OPTIONS π
new
(class constructor)
Accepts: An optional hash of configuration options.
Returns: A new instance of the XML::Generator::PerlData class.
Creates a new instance of XML::Generator::PerlData.
Basic usage is designed to be simple and straightforward, but there's a whole lil' host of options available so the SAX event streams β and by extension the XML documents β that get created from your data structures come out in exactly the format you want. β¨
Options
Handler(required) βXML::Generator::PerlDatais a SAX Driver/Generator, so it needs a SAX Handler or Filter class to forward its events to. The value for this option must be an instance of a SAX2-aware Handler or Filter.rootname(optional) β sets the name of the top-level (root) element. Default is'document'.defaultname(optional) β sets the default name used for elements when no other logical name is available (think lists-of-lists π« ). Default is'default'.keymap(optional) β okay so, the names of the keys in a given hash often don't map directly to the XML element names you want in the resulting document. This option holds a set of keyname->element name mappings for the current process.skipelements(optional) β passed in as an array reference, this sets the internal list of keynames that get skipped over during processing. Heads up: any descendant structures belonging to those keys get skipped too. πattrmap(optional) β determines which 'children' of a given hash key/element-name get forwarded as attributes of that element instead of as child elements.
(see CAVEATS for a whole discussion of this method's limitations.)
namespaces(optional) β sets the internal list of namespace/prefix pairs for the current process. It takes the form of a hash, where the keys are the URIs of the given namespace and the values are the associated prefix.
To set a default (unprefixed) namespace, set the prefix to '#default'.
namespacemap(optional) β sets which elements in the result get bound to which declared namespaces. It takes the form of a hash of key/value pairs where the keys are one of the declared namespace URIs relevant to the current process, and the values are either single key/element names or an array reference of key/element names.skiproot(optional) β when set to a defined value, this blocks the generator from adding the top-level root element whenparse()orparse_start()andparse_end()are called.
π¨ Do NOT use this option unless you are absolutely, 100%, no-cap sure you know what you're doing and why β the resulting event stream will most likely produce non-well-formed XML. Like, most likely. Be so for real right now.
bindattrs(optional) β when set to a defined value, this tells the generator to bind attributes to the same namespace as the element that contains them. By default, attributes will be unbound and unprefixed.processing_instructions(optional) β this option is your way to include XML processing instructions events into the generated stream before the root element is emitted. The value of this key can be either a hash reference or an array reference of hash references. For example, when connected toXML::SAX::Writer:
$pd->new( Handler => $writer_instance,
rootname => 'document',
processing_instructions => {
'xml-stylesheet' => {
href => '/path/to/stylesheet.xsl',
type => 'text/xml',
},
});
would generate
<?xml version="1.0"?>
<?xml-stylesheet href="/path/to/stylesheet.xsl" type="text/xsl" ?>
<document>
...
Where multiple processing instructions will have the same target and/or where the document order of those PIs matters, an array reference should be used instead. For example:
$pd->new( Handler => $writer_instance,
rootname => 'document',
processing_instructions => [
'xml-stylesheet' => {
href => '/path/to/stylesheet.xsl',
type => 'text/xml',
},
'xml-stylesheet' => {
href => '/path/to/second/stylesheet.xsl',
type => 'text/xml',
}
]);
would produce:
<?xml version="1.0"?>
<?xml-stylesheet href="/path/to/stylesheet.xsl" type="text/xsl" ?>
<?xml-stylesheet href="/path/to/second/stylesheet.xsl" type="text/xsl" ?>
<document>
...
π¦ PROCESSING METHODS π¦
Simple style processing
parse
Accepts: A reference to a Perl data structure. Optionally, a hash of config options.
Returns: [none]
The core method used during 'simple style' processing π It accepts a reference to a Perl data structure and, based on the options passed, produces a stream of SAX events that can be used to transform that structure into XML. The optional second argument is a hash of config options identical to those detailed in the OPTIONS section of the the new() constructor description.
Examples:
$pd->parse( \%my_hash );
$pd->parse( \%my_hash, rootname => 'recordset' );
$pd->parse( \@my_list, %some_options );
$pd->parse( $my_hashref );
$pd->parse( $my_arrayref, keymap => { default => ['foo', 'bar', 'baz'] } );
Stream style processing
parse_start
Accepts: An optional hash of config options.
Returns: [none]
Starts the SAX event stream and (unless configured not to) fires the event for the top-level root element π₯ The optional argument is a hash of config options identical to those detailed in the OPTIONS section of the the new() constructor description.
Example:
$pd->parse_start();
parse_end
Accepts: [none].
Returns: Varies. Returns what the final Handler returns.
Ends the SAX event stream and (unless configured not to) fires the event to close the top-level root element. π
Example:
$pd->parse_end();
parse_chunk
Accepts: A reference to a Perl data structure.
Returns: [none]
The core method used during 'stream style' processing β it accepts a reference to a Perl data structure and, based on the options passed, produces a stream of SAX events that can be used to transform that structure into XML. β¨
Examples:
$pd->parse_chunk( \%my_hash );
$pd->parse_chunk( \@my_list );
$pd->parse_chunk( $my_hashref );
$pd->parse_chunk( $my_arrayref );
π CONFIGURATION METHODS π
All config options can be passed to calls to the new() constructor using the typical "hash of named properties" syntax. The methods below give you direct access to the individual options (or ways to add/remove the smaller definitions those options contain). iykyk π
init
Accepts: The same configuration options that can be passed to the new() constructor.
Returns: [none]
See the list of OPTIONS above in the definition of new() for details.
rootname
Accepts: A string or [none].
Returns: The current root name.
When called with an argument, this method sets the name of the top-level (root) element. It always returns the name of the current (or new) root name. π«Ά
Examples:
$pd->rootname( $new_name );
my $current_root = $pd->rootname();
defaultname
Accepts: A string or [none]
Returns: The current default element name.
When called with an argument, this method sets the name of the default element. It always returns the name of the current (or new) default name. πΈ
Examples:
$pd->defaultname( $new_name );
my $current_default = $pd->defaultname();
keymap
Accepts: A hash (or hash reference) containing a series of keyname->elementname mappings or [none].
Returns: The current keymap hash (as a plain hash, or hash reference depending on caller context). π
When you hand it a hash (or a hashref) as its argument, this method sets/resets the entire internal keyname->elementname mappings definitions in one go β and bestie, quick vocab check: 'keyname' means the name of a given key in the hash, and 'elementname' is the name that gets used when firing SAX events for that key. π
And it's not just plain name->othername swaps, okay? The value of a keymap option can also be a reference to a subroutine (or an anonymous sub). The keyname gets passed as the sole argument to that sub, and the sub is expected to return the new element name. In the cases of nested arrayrefs, no keyname will be passed β but you can still generate the name from scratch. β¨
Extending that idea, keymap will also accept a default mapping using the key '*', and that gets applied to all elements that do have an explicit mapping configured. π«
To add new mappings or remove existing ones without having to reset the whole entire list of mappings, go see add_keymap() and delete_keymap() respectively. π«Ά
β οΈ If you are using "stream style" processing, this method should be used with caution, since altering this mapping during processing may result in not-well-formed XML. Not the vibe you want, fr fr. π
Examples:
$pd->keymap( keyname => 'othername',
anotherkey => 'someothername' );
$pd->keymap( \%mymap );
# make all tags lower case
$pd->keymap( '*' => sub{ return lc( $_[0];} );
# process keys named 'keyname' with a local sub
$pd->keymap( keyname => \&my_namer,
my %kmap_hash = $pd->keymap();
my $kmap_hashref = $pd->keymap();
add_keymap
Accepts: a hash (or hash reference) containing a series of keyname->elementname mappings.
Returns: [none]
Adds a series of keyname->elementname mappings β again, 'keyname' is the name of a given key in the hash, and 'elementname' is the name used when firing SAX events for that key. π¦
Examples:
$pd->add_keymap( keyname => 'othername' );
$pd->add_keymap( \%hash_of_mappings );
delete_keymap
Accepts: a list (or array reference) of element/keynames.
Returns: [none]
Deletes a list of keyname->elementname mappings (where 'keyname' = the name of a given key in the hash, and 'elementname' = the name used when firing SAX events for that key). ποΈ
β οΈ This method should be used with caution, since altering this mapping during processing may result in not-well-formed XML. Iconic behavior? No, it's giving chaos. π
Examples:
$pd->delete_keymap( 'some', 'key', 'names' );
$pd->delete_keymap( \@keynames );
skipelements
Accepts: a list (or array reference) containing a series of key/element names, or [none].
Returns: the current skipelements array (as a plain list, or array reference, depending on caller context).
When called with an array (array reference) as its argument, this method sets/resets the entire internal skipelement definitions β and that's the thing that determines which keys will not be 'parsed' during processing. π
To add new mappings or remove existing ones without resetting the whole list of mappings, see add_skipelements() and delete_skipelements() respectively. π
Examples:
$pd->skipelements( 'elname', 'othername', 'thirdname' );
$pd->skipelements( \@skip_names );
my @skiplist = $pd->skipelements();
my $skiplist_ref = $pd->skipelements();
add_skipelements
Accepts: a list (or array reference) containing a series of key/element names.
Returns: [none]
Adds a list of key/element names to skip during processing. Simple as that, no notes. πΈ
Examples:
$pd->add_skipelements( 'some', 'key', 'names' );
$pd->add_skipelements( \@keynames );
delete_skipelements
Accepts: a list (or array reference) containing a series of key/element names.
Returns: [none]
Deletes a list of key/element names to skip during processing. βοΈ
Examples:
$pd->delete_skipelements( 'some', 'key', 'names' );
$pd->delete_skipelements( \@keynames );
charmap
Accepts: a hash (or hash reference) containing a series of parent/child keyname pairs, or [none].
Returns: the current charmap hash (as a plain hash, or hash reference, depending on caller context).
When called with a hash (hash reference) as its argument, this method sets/resets the entire internal keyname/elementname->characters children mappings definitions. Decoder ring time: 'keyname' means the name of a given key in the hash, and 'characters children' is a list containing the nested keynames that should be passed as the text children of the element named 'keyname' β instead of being processed as child elements or attributes. π§
To add new mappings or remove existing ones without resetting the whole list of mappings, see add_charmap() and delete_charmap() respectively. β¨
π See CAVEATS for the limitations that relate to this method. Don't skip that part, bestie, it matters.
Examples:
$pd->charmap( elname => ['list', 'of', 'nested', 'keynames' );
$pd->charmap( \%mymap );
my %charmap_hash = $pd->charmap();
my $charmap_hashref = $pd->charmap();
add_charmap
Accepts: a hash or hash reference containing a series of parent/child keyname pairs.
Returns: [none]
Adds a series of parent-key -> child-key relationships that define which of the possible child keys will be processed as text children of the created 'parent' element. π
Examples:
$pd->add_charmap( parentname => ['list', 'of', 'child', 'keys'] );
$pd->add_charmap( parentname => 'childkey' );
$pd->add_charmap( \%parents_and_kids );
delete_charmap
Accepts: a list (or array reference) of element/keynames.
Returns: [none]
Deletes a list of parent-key -> child-key relationships from the instance-wide hash of "parent->nested names to pass as text children" definitions. Heads up: if you need to alter the list of child names (without deleting the parent key), use add_charmap() to reset the parent-key's definition. π
Examples:
$pd->delete_charmap( 'some', 'parent', 'keys' );
$pd->delete_charmap( \@parentkeynames );
attrmap
Accepts: a hash (or hash reference) containing a series of parent/child keyname pairs, or [none].
Returns: the current attrmap hash (as a plain hash, or hash reference, depending on caller context).
When called with a hash (hash reference) as its argument, this method sets/resets the entire internal keyname/elementname->attr children mappings definitions β where 'keyname' means the name of a given key in the hash, and 'attr children' is a list containing the nested keynames that should be passed as attributes of the element named 'keyname' (instead of as child elements). π
To add new mappings or remove existing ones without resetting the whole list of mappings, see add_attrmap() and delete_attrmap() respectively. π«Ά
π See CAVEATS for the limitations that relate to this method. Yes, same warning, go read it.
Examples:
$pd->attrmap( elname => ['list', 'of', 'nested', 'keynames' );
$pd->attr( \%mymap );
my %attrmap_hash = $pd->attrmap();
my $attrmap_hashref = $pd->attrmap();
add_attrmap
Accepts: a hash or hash reference containing a series of parent/child keyname pairs.
Returns: [none]
Adds a series of parent-key -> child-key relationships that define which of the possible child keys will be processed as attributes of the created 'parent' element. β
Examples:
$pd->add_attrmap( parentname => ['list', 'of', 'child', 'keys'] );
$pd->add_attrmap( parentname => 'childkey' );
$pd->add_attrmap( \%parents_and_kids );
delete_attrmap
Accepts: a list (or array reference) of element/keynames.
Returns: [none]
Deletes a list of parent-key -> child-key relationships from the instance-wide hash of "parent->nested names to pass as attributes" definitions. And same energy as before: if you need to alter the list of child names (without deleting the parent key), use add_attrmap() to reset the parent-key's definition. π
Examples:
$pd->delete_attrmap( 'some', 'parent', 'keys' );
$pd->delete_attrmap( \@parentkeynames );
bindattrs
Accepts: 1 or 0 or [none].
Returns: undef or 1, based on the current state of the bindattrs option.
Okay so consider:
<myns:foo bar="quux"/>
and
<myns:foo myns:bar="quux"/>
These two are not functionally equivalent. Not the same thing, not a vibe match, no. π
By default, attributes will be forwarded as not being bound to the namespace of the containing element (like the first example up there βοΈ). Setting this option to a true value alters that behavior. π₯
Examples:
$pd->bindattrs(1); # attributes now bound and prefixed.
$pd->bindattrs(0);
my $is_binding = $pd->bindattrs();
add_namespace
Accepts: a hash containing the defined keys 'uri' and 'prefix'.
Returns: [none]
Add a namespace URI/prefix pair to the instance-wide list of XML namespaces that will be used while processing. And here's the tea: the reserved prefix '#default' can be used to set the default (unprefixed) namespace declaration for elements. π
Examples:
$pd->add_namespace( uri => 'http://myhost.tld/myns',
prefix => 'myns' );
$pd->add_namespace( uri => 'http://myhost.tld/default',
prefix => '#default' );
See namespacemap() or the namespacemap option detailed in new() for details about how to associate a key/element name with a given namespace. π
namespacemap
Accepts: a hash (or hash reference) containing a series of uri->key/element name mappings, or [none].
Returns: the current namespacemap hash (as a plain hash, or hash reference, depending on caller context).
When called with a hash (hash reference) as its argument, this method sets/resets the entire internal namespace URI->keyname/elementname mappings definitions β where 'keyname' means the name of a given key in the hash, and 'namespace URI' is a declared namespace URI for the given process. π¦
To add new mappings or remove existing ones without resetting the whole list of mappings, see add_namespacemap() and delete_namespacemap() respectively. β¨
β οΈ If you are using "stream style" processing, this method should be used with caution, since altering this mapping during processing may result in not-well-formed XML. Same warning, same stakes. π
Examples:
$pd->add_namespace( uri => 'http://myhost.tld/myns',
prefix => 'myns' );
$pd->namespacemap( 'http://myhost.tld/myns' => elname );
$pd->namespacemap( 'http://myhost.tld/myns' => [ 'list', 'of', 'elnames' ] );
$pd->namespacemap( \%mymap );
my %nsmap_hash = $pd->namespacemap();
my $nsmap_hashref = $pd->namespacemap();
π§ add_namespacemap
- Accepts: a hash (or a hashref) stuffed with a whole series of
uriβ key/element name mappings - Returns:
[none]β nothing, bestie, it's a vibe-only method π
It adds one or more namespace β element/keyname rules to the instance-wide list of mappings. Think of it as pinning new rules to the corkboard π
Examples, iconically:
$pd->add_namespacemap( 'http://myhost.tld/foo' => ['some', 'list', 'of' 'keys'] );
$pd->add_namespacemap( %new_nsmappings );
πΈ remove_namespacemap
- Accepts: a list (or an array reference) of element/keynames
- Returns:
[none]
It removes a list of namespace β element/keyname rules to the instance-wide list of mappings. (Yes babes, the description literally says "removes... to the list." We don't question the lore, we just report it π«Ά)
Examples:
$pd->delete_namespacemap( 'foo', 'bar', 'baz' );
$pd->delete_namespacemap( \@list_of_keynames );
π₯ SAX EVENT METHODS π₯
As a subclass of XML::SAX::Base, XML::Generator::PerlData lets you call all of the SAX event methods directly so you can insert arbitrary events into the stream whenever you need to. And yes β using it this way is probably a Bad Thing, and it's only relevant to "stream style" processing. But it's good to know that such fine-grained access is there if you need it. It's giving "secret menu item" π
Okay so with that disclaimer aside β there may be cases (again, "stream style" only) where you'll want to insert single elements into the output. Like wrapping each array in a series of arrays in single 'record' elements. Very that. π
The following methods simplify the whole task: you pass in simple element name strings and the result 'just work's β no expert knowledge of the Perl SAX2 implementation required, and no forcing you to keep track of things like namespace context. slay β¨
β οΈ Take care to ensure that every call tostart_tag()has a corresponding call toend_tag()or your documents will not be well-formed. Not me warning you about malformed XML, this is serious bestie π
π start_tag
- Accepts: a string containing an element name, plus an optional hash of simple key/value attributes
- Returns:
[none]
Examples:
$pd->start_tag( $element_name );
$pd->start_tag( $element_name, id => $generated_id );
$pd->start_tag( $element_name, %some_attrs );
π¦ end_tag
- Accepts: a string containing an element name
- Returns:
[none]
Examples:
$pd->end_tag( $element_name );
π CAVEATS π
Okay so in general, XML is built on the idea that every single bit of data is gonna have a corresponding name (Elements, Attributes, etc.). Which is not at all a Bad Thing! But it does mean that some Perl data structures do not map cleanly onto an XML representation. Sad but true π
Consider this:
my %hash = ( foo => ['one', 'two', 'three'] );
How do you even represent that as XML? Is it three 'foo' elements? Or is it a 'foo' parent element with 3 mystery children? Spooky. XML::Generator::PerlData chooses the former. So:
<foo>one</foo>
<foo>two</foo>
<foo>three</foo>
Now consider:
my @lol = ( ['one', 'two', 'three'], ['four', 'five', 'six'] );
In this case you wind up with a pile of elements named 'default'. You can work around this by doing $pd->add_keymap( default => ['list', 'of', 'names'] ) β but that only works if you know how many entries are going to be in each nested list. F in the chat for dynamic data π
The practical implication here: the current version of XML::Generator::PerlData favors data structures that are based on hashes of hashes for deeply nested structures (especally when using Simple Style processing), and some options like "attrmap" do not work for arrays at all. Future versions will address these issues if sanely possible. manifesting that for the future π
π AUTHOR π
Kip Hampton, khampton@totalcinema.com
π COPYRIGHT π
(c) Kip Hampton, 2002-2014, All Rights Reserved.
β¨ LICENSE β¨
This module is released under the Perl Artistic Licence and may be redistributed under the same terms as perl itself.
π SEE ALSO π
XML::SAX, XML::SAX::Writer.
And that's a wrap on the whole page, bestie!! π This one shipped as perl v5.36.0 dated 2022-11-20, and the page itself is PerlData(3pm) β go forth and generate some truly iconic XML, you absolute legend π«Άβ¨π
π¦ where this page comes from
- debian bookworm: libxml-generator-perldata-perl 0.95-3 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- debian trixie: libxml-generator-perldata-perl 0.95-3 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libxml-generator-perldata-perl 0.95-3 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libxml-generator-perldata-perl 0.95-3 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libxml-generator-perldata-perl 0.95-3 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms