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


XML-Writer-Nest documentation Contained in the XML-Writer-Nest distribution.

Index


Code Index:

NAME

Top

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

SYNOPSIS

Top

    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

Top

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

Top

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

Top

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

Top

Terrence Brannon, <metaperl at gmail.com>

SEE ALSO

Top

"Constructive Use of Destructors"

http://www.metaperl.org/publications

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

BUGS

Top

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

Top

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

    perldoc XML::Writer::Nest




You can also look for information at:

* RT: CPAN's request tracker

http://rt.cpan.org/NoAuth/Bugs.html?Dist=XML-Writer-Nest

* AnnoCPAN: Annotated CPAN documentation

http://annocpan.org/dist/XML-Writer-Nest

* CPAN Ratings

http://cpanratings.perl.org/d/XML-Writer-Nest

* Search CPAN

http://search.cpan.org/dist/XML-Writer-Nest/

ACKNOWLEDGEMENTS

Top

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

COPYRIGHT & LICENSE

Top


XML-Writer-Nest documentation Contained in the XML-Writer-Nest distribution.

package XML::Writer::Nest;

our $VERSION = '1.0';

use Moose;
has 'tag'    => (isa => 'Str', is => 'ro', required => 1);
has 'attr'   => (isa => 'ArrayRef[Maybe[Str]]',    is => 'ro', default => sub { [] } ); # hashref wont preserve order!
has 'writer' => (isa => 'XML::Writer', is => 'ro', required => 1);


use XML::Writer;

sub nest {
    my($self, $tag, @attr)=@_;

    my @nattr;

    if (scalar @attr and ref $attr[0] eq 'ARRAY') {
	@nattr = @{$attr[0]};
    } else {
	@nattr = @attr;
    }

    XML::Writer::Nest->new(tag => $tag, attr => \@nattr, writer => $self->writer);
}
    
    

sub BUILD {
    my($self)=@_;

    my @attr = defined($self->attr) ? @{$self->attr} : () ;

    #warn "Writer" . $self->writer;
    
    $self->writer->startTag($self->tag, @attr);

    $self;
}
 
sub DEMOLISH {
    my($self)=@_;

    $self->writer->endTag();
}



1; # End of XML::Writer::Nest