NAME

XML::Writer::Nest - dataElement() for when you need to embed elements, not data

SYNOPSIS

use XML::Writer::Nest;

 my $writer = new XML::Writer;

 {  my $level1 = XML::Writer::Nest->new(tag => 'level1', attr => [ hee => 'haw', fee => 'fi' ], writer => $writer  );

    {  my $level2 = $level1->nest(level2 => [ attr1 => 3 ] ); # or call the class conc. again.
 
       {  my $level3 = $level2->nest('level3');

       } # endTag created automatically

    } # endTag created automatically

} # endTag created automatically

Vanilla XML::Writer would not have indentation and you would have to manually close your start tags:

$writer->startTag("level1");
$writer->startTag("level2");
$writer->startTag("level3");
$writer->endTag();
$writer->endTag();
$writer->endTag();

DESCRIPTION

When nesting XML elements with XML::Writer, you have to manually close your startTags. Also, you dont necessarily have any visual feedback via indentation for each level of tag nesting.

XML::Writer::Nest solves both of those problems.

XML::Generator

XML::Generator solves this problem a different way. But I dont see an easy way to make use of object-oriented dispatch to specialize and generalize XML production with it.

My current module and Moose's inner work just fine together.

API

There is a class-level constructor and an object-level constructor. The class level constructor requires 3 arguments (tag, attributes, and XML::Writer instance). The object-level constructor only requires tag and attribute arguments - it passes along the XML::Writer instance.

NOTE: This module operates based on lexical scope. So both object and class level construction are done right after creating a new lexical scope with braces.

Class-based constructor

{ my $xml_nest = XML::Writer::Nest->new(tag => 'tagname', attr => \@attr, writer => $xml_writer);

  # add some additional things for this nest level via $xml_writer->api_calls
} # when $xml_nest goes out of scope, it calls $xml_writer->endTag automatically

Object-based constructor

{ my $xml_nest2 = $xml_nest->nest(tagname => \@attr);

  # add some additional things for this nest level via $xml_writer->api_calls
} # when $xml_nest2 goes out of scope, it calls $xml_writer->endTag automatically

{ my $xml_nest2 = $xml_nest->nest(tagname => @attr);

  # add some additional things for this nest level via $xml_writer->api_calls
} # when $xml_nest2 goes out of scope, it calls $xml_writer->endTag automatically

Please note: the object-level constructor will either an arrayref or array of attributes. The class-based constructor will take only an arrayref of attributes.

DISCUSSION

Caveat emptor

If you wish to nest elements at the same level ("sibling elements"), then you must brace each:

#!/usr/bin/perl

use strict;
use XML::Writer::Nest;

my $output;
my $writer = new XML::Writer(OUTPUT => $output);
my $main = new XML::Writer::Nest(tag => 'main', writer => $writer);

{
    my $head = $main->nest('head');

}
{
    my $body = $main->nest('body');
}

print STDOUT $output . "\n\n";

XML::Generator

XML::Generator is another module which allows for automatic creation of closing tags based on behavior of the Perl programming language.

From what I can see, one is not able to leverage object-oriented re-use of parts of the XML generation by delegating specialized aspects of the rendering to subclasses.

Concretely, Moose's augment function has demonstrated a way of allowing generic and specific aspects of XML generation to co-operate.

Therefore, I like Moose in combination with XML::Writer for object-oriented XML production. However, the automatic creation of closing XML tags by XML::Generator is quite attractive. Not only that, but the automatic source-code indentation is especially handy when you are creating highly nested XML.

Another thing I don't like about XML::Generator is that you must use one highly nested function call to produce the output document. I prefer brace-levels and a series of calls to the XML::Writer interface.

Practical Comparison

Let's take the synopsis example from XML::Generator and write it in all 3 approaches. First let's take a look at the desired XML output.

<foo xmlns:qux="http://qux.com/">
   <bar baz="3">
     <bam />
   </bar>
   <qux:bar>Hey there, world</qux:bar>
 </foo>

XML::Generator

use XML::Generator ':pretty';

print foo(bar({ baz => 3 }, bam()),
          bar([ 'qux' => 'http://qux.com/' ],
                "Hey there, world"));

AUTHOR

Terrence Brannon, <metaperl at gmail.com>

SEE ALSO

"Constructive Use of Destructors"

http://www.metaperl.org/publications

This talk to the Columbus, OH Perl mongers discusses XML::Writer::Nest in detail.

BUGS

Please report any bugs or feature requests to bug-xml-writer-nest at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=XML-Writer-Nest. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc XML::Writer::Nest

You can also look for information at:

ACKNOWLEDGEMENTS

Many thanks to #moose, especially Jeese Luehrs (doy)!, matt trout, doy, and confound.

COPYRIGHT & LICENSE

Copyright 2009 Terrence Brannon, all rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.