=head1 NAME XML::XMLWriter - Module for creating a XML document object oriented with on the fly validating towards the given DTD. =cut ###################################################################### package XML::XMLWriter; require 5.8.0; # Copyright (c) 2003, Moritz Sinn. This module is free software; # you can redistribute it and/or modify it under the terms of the # GNU GENERAL PUBLIC LICENSE, see COPYING for more information. use strict; use vars qw($VERSION); $VERSION = '0.1'; ###################################################################### =head1 DEPENDENCIES =head2 Perl Version 5.004 =head2 Standard Modules Carp 1.01 Encode 1.98 =head2 Nonstandard Modules XML::ParseDTD 0.1.3 =cut ###################################################################### use Carp; use Encode; use XML::ParseDTD; use XML::XMLWriter::Element; ###################################################################### =head1 SYNOPSIS =head2 Example Code #!/usr/bin/perl use XML::XMLWriter; my @data=(['Name', 'Adress', 'Email', 'Sex'], ['Herbert', 'BeerAvenue 45', 'herbert@names.org', 'Male'], ['Anelise', 'SchmidtStreet 21', 'foo@bar.com', 'Female'], ['XYZ', 'ZYX', 'ZY', 'XZ'], ['etc...']); my $doc = new XML::XMLWriter(system => 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd', public => '-//W3C//DTD XHTML 1.0 Transitional//EN'); my $html = $doc->createRoot; $html->head->title->_pcdata('A Table'); my $body = $html->body; $body->h1->_pcdata('Here is a table!'); my $table = $body->table({align => 'center', cellspacing => 1, cellpadding => 2, border => 1}); for(my $i=0; $i<@data; $i++) { my $tr = $table->tr; foreach $_ (@{$data[$i]}) { $i==0 ? $tr->th->_pcdata($_) : $tr->td->_pcdata($_); } } $body->b->_pcdata("that's it!"); $doc->print(); =head2 Example Output A Table

Here is a table!

NameAdressEmailSex
HerbertBeerAvenue 45herbert@names.orgMale
AneliseSchmidtStree 21foo@bar.comFemale
XYZZYXZYXZ
etc...
that's it! =head1 DESCRIPTION XMLWriter is a Perl 5 object class, its purpose is to make writing XML documents easier, cleaner, safer and standard conform. Its easier because of the object oriented way XML documents are written with XMLWriter. Its cleaner because of the simple but logical API and its safe and standard conform because of the automatically done checking against the the DTD. But still: it might be a matter of taste whether one finds XMLWriter usefull or not and it probably has some bugs (i would appreciate a lot if you report them to me), many usefull features are missing, not implemented or not even thought of and perhaps the API with all its simpleness might be confusing though. So please tell me your opinion and tell me the way how you would make XMLWriter better. Its not so easy to develop a good API for this matter. XMLWriter contains 3 packages: XMLWriter.pm which gives you the document object, Element.pm which provides the element/tag objects and PCData.pm which represents the parsed character data the document contains. There'll probably come more objects in feature releases. The most interesting class is Element.pm. It provides some methods you can call on every document element, but besides those methods it uses the I feature of perl to expect every not known method name to be the name of a tag that should be added to the list of child tags of the element the method is called on. So calling C<$html-Ehead> will simply add a new element (the head element) to the list of child tags of the html element. The head object is returned. Have a look at the examples for better understanding. You should also read the POD of Element.pm and PCdata.pm. =head1 USING XML::XMLWriter =head2 Encoding All methods expect the data you pass them to be encoded in UTF8. So if you take data with diffrent encoding call I to make it UTF8. Finally the whole document will be encoded in the document encoding (default: UTF8) before being returned. =head2 The Constructor =head3 new ([ %conf ]) The only argument can be a hash setting some configuration options: =over =item version - XML version, defaults to I<1.0>, shouldn't be changed. =item encoding - Character encoding. Defaults to I. =item public - PUBLIC IDENTIFIER. Defaults to I<-//W3C//DTD XHTML 1.0 Strict//EN>. =item system - SYSTEM IDENTIFIER (must always be a path/url pointing to a valid dtd). Defaults to I. =item standalone - sets the I option of the XML declaration. Defaults to I, the only other possible value is I. =item root - sets the name of the root element. Defaults to I. =item rootArgs - sets the list of arguments and their values for the root element. Defaults to I<{}> (empty hash reference). =item intend - sets whether intentation should be done and if so how many spaces per level. Defaults to 0, is not implemented yet, that means setting it won't have any effect. =item checklm - the value of this option is passed to XML::ParseDTD for setting its I parameter. Please the the documentation of XML::ParseDTD for more information. Defaults to I<-1>. =back =cut ###################################################################### sub new { my ($class, %conf) = @_; my $self = bless({}, ref($class) || $class); $self->{Conf} = { version => '1.0', encoding => 'UTF8', #encoding => 'ISO-8859-15', public => '-//W3C//DTD XHTML 1.0 Strict//EN', system => 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd', standalone => 'no', root => 'html', rootArgs => {}, #intend => 2, intend => 0, checklm => -1, }; local $_; foreach $_ (keys(%conf)) { $self->{Conf}->{$_} = $conf{$_}; } return $self; } ###################################################################### =head2 Methods =head3 createRoot ([$rootelem, %arguments, $character_data]) Creates the root element and returns a I object representing it. Possible parameters: =over =item 1. The root elements name. Defaults to the value of the I configuration option (see the C method). =item 2. A hash of arguments for the root element and their values. Defaults to the value of the I configuration option (see the C method). =item 3. A string of character data which will be appended right after the start tag. Defaults to undef, which means no data will be added. =back Instead of passing the third argument you can also just do a C<$root-E_pcdata(yourdata)>, its exactly the same. =cut ###################################################################### sub createRoot { my ($self,$root,%args,$text) = @_; $self->{dtd} = XML::ParseDTD->new($self->{Conf}->{system},checklm => $self->{Conf}->{checklm}) if($self->{Conf}->{system}); $self->{root} = XML::XMLWriter::Element->new(($root||$self->{Conf}->{root}),$self->{dtd},(\%args||$self->{Conf}->{rootArgs}),$text); return $self->{root}; } ###################################################################### =head3 get () Returns the XML document as a string. Every elements child list is checked and a warning is produce if its not allowed by the DTD. =cut ###################################################################### sub get { my ($self) = @_; local $_ = '{Conf}->{version} . '" encoding="' . $self->{Conf}->{encoding} . '" standalone="' . $self->{Conf}->{standalone} . '"?>' . "\n"; $_ .= '{Conf}->{root} . ($self->{Conf}->{public} ? ' PUBLIC "' . $self->{Conf}->{public} . '"' : '') . ($self->{Conf}->{system} ? ' SYSTEM "' . $self->{Conf}->{system} . '"' : '') . ">\n"; return encode($self->{Conf}->{encoding},$_ . $self->{root}->_get()); } ###################################################################### =head3 print () Prints the XML document to STDOUT. =cut ###################################################################### sub print { my ($self,$html) = @_; print $self->get($html); } ###################################################################### =head3 get_dtd () Returns the internally used C object. =cut ###################################################################### sub get_dtd { my($self) = @_; return $self->{dtd}; } return 1; __END__ #sub get_doc { # my($self) = @_; # return $self->{doc}; #} #sub validate { # my($self) = @_; # return $self->{doc}->validate(); #} #sub is_valid { # my($self) = @_; # return $self->{doc}->is_valid(); #}