File Coverage

blib/lib/XML/DOM/BagOfTricks.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package XML::DOM::BagOfTricks;
2 1     1   890 use strict;
  1         2  
  1         48  
3              
4             =head1 NAME
5              
6             XML::DOM::BagOfTricks - Convenient XML DOM
7              
8             =head1 SYNOPSIS
9              
10             use XML::DOM::BagOfTricks;
11              
12             # get the XML document and root element
13             my ($doc,$root) = createDocument('Foo');
14              
15             # or
16              
17             # get the XML document with xmlns and version attributes specified
18             my $doc = createDocument({name=>'Foo', xmlns=>'http://www.other.org/namespace', version=>1.3});
19              
20             # get a text element like Bar
21             my $node = createTextElement($doc,'Foo','Bar');
22              
23             # get an element like
24             my $node = createElement($doc,'Foo','isBar'=>0, 'isFoo'=>1);
25              
26             # get a nice element with attributes that contains a text node Bar
27             my $foo_elem = createElementwithText($DOMDocument,'Foo','Bar',isFoo=>1,isBar=>0);
28              
29             # add attributes to a node
30             addAttributes($node,foo=>'true',bar=>32);
31              
32             # add text to a node
33             addText($node,'This is some text');
34              
35             # add more elements to a node
36             addElements($node,$another_node,$yet_another_node);
37              
38             # adds two text nodes to a node
39             addTextElements($node,Foo=>'some text',Bar=>'some more text');
40              
41             # creates new XML:DOM::Elements and adds them to $node
42             addElements($node,{ name=>'Foo', xlink=> 'cid:..' },{ .. });
43              
44             # extracts the text content of a node (and its subnodes)
45             my $content = getTextContents($node);
46              
47             =head1 DESCRIPTION
48              
49             XML::DOM::BagOfTricks provides a bundle, or bag, of functions that make
50             dealing with and creating DOM objects easier.
51              
52             The goal of this BagOfTricks is to deal with DOM and XML in a more perl
53             friendly manner, using native idioms to fit in with the rest of a perl
54             program.
55              
56             As of version 0.02 the API has changed to be clearer and more in line with
57             the DOM API in general, now using createFoo instead of getFoo to create
58             new elements, documents, etc.
59              
60             =cut
61              
62              
63 1     1   2227 use XML::DOM;
  0            
  0            
64              
65             require Exporter;
66             use AutoLoader qw(AUTOLOAD);
67              
68             our $VERSION = '0.05';
69             our @ISA = qw(Exporter);
70             our %EXPORT_TAGS = ( 'all' => [ qw(
71             &getTextContents
72             &createDocument &createTextElement &createElement &createElementwithText
73             &addAttributes &addText &addElements &addTextElements
74             ) ] );
75             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
76              
77             =head2 createTextElement($doc,$name,$value)
78              
79             This function returns a nice XML::DOM::Node representing an element
80             with an appended Text subnode, based on the arguments provided.
81              
82             In the example below $node would represent 'Bar'
83              
84             my $node = getTextElement($doc,'Foo','Bar');
85              
86             More useful than a pocketful of bent drawing pins!
87              
88             When called with no text value defined, will just return a normal
89             element without a textnode attached so the example below would
90             return a node representing ''
91              
92             my $node = getTextElement($doc,'Foo');
93              
94             =cut
95              
96             sub createTextElement {
97             my ($doc, $name, $value) = @_;
98             die "createTextElement requires a name : ", caller() unless $name;
99             my $field = $doc->createElement($name);
100             if (defined $value) {
101             my $fieldvalue = $doc->createTextNode($value);
102             $field->appendChild($fieldvalue);
103             }
104             return $field;
105             }
106              
107             =head2 createElement($doc,$name,%attributes)
108              
109             This function returns a nice XML::DOM::Node representing an element
110             with an appended Text subnode, based on the arguments provided.
111              
112             In the example below $node would represent ''
113              
114             my $node = createElement($doc,'Foo','isBar'=>0, 'isFoo'=>1);
115              
116             Undefined attributes will be ignored, if you want to set an attribute value
117             as an empty value pass it an empty string like ''.
118              
119             =cut
120              
121              
122             sub createElement {
123             my ($doc, $name, @attributes) = @_;
124             my $node = $doc->createElement($name);
125             while (@attributes) {
126             my ($name,$value) = (shift @attributes, shift @attributes);
127             $node->setAttribute($name,$value) if ($name);
128             }
129              
130             return $node;
131             }
132              
133              
134             =head2 createElementwithText($DOMDocument,$node_name,$text,$attr_name=>$attr_value);
135              
136             # get a nice element with attributes that contains a text node ( i.e. Bar )
137             my $foo_elem = getElementwithText($DOMDocument,'Foo','Bar',isFoo=>1,isBar=>0);
138              
139             The order of attributes is preserved with this method, other methods may not do so.
140              
141             =cut
142              
143             sub createElementwithText {
144             my ($doc, $nodename, $textvalue, @attributes) = @_;
145             die "getElementwithText requires a DOMDocument ", caller() unless (ref $doc);
146             die "getElementwithText requires a name : ", caller() unless $nodename;
147             my $node = $doc->createElement($nodename);
148             if ($textvalue) {
149             my $text = $doc->createTextNode($textvalue);
150             $node->appendChild($text);
151             }
152             while (@attributes) {
153             my ($name,$value) = (shift @attributes, shift @attributes);
154             $node->setAttribute($name,$value) if ($name);
155             }
156              
157             return $node;
158             }
159              
160              
161             =head2 addAttributes
162              
163             Adds attributes to a provided XML::DOM::Node. Based on set_atts from XML::DOM::Twig by Michel Rodriguez.
164              
165             addAttributes($node,foo=>'true',bar=>32);
166              
167             Returns the modified node
168              
169             The order of attributes is preserved with this method, other methods may not do so.
170              
171             =cut
172              
173             # based on set_atts from XML::DOM::Twig by Michel Rodriguez
174             sub addAttributes {
175             my $node = shift;
176             while (@_) {
177             $node->setAttribute(shift,shift) if ($_[0]);
178             }
179             return $node;
180             }
181              
182             =head2 addElements
183              
184             Adds elements to a provided XML::DOM::Element. Based on set_content from XML::DOM::Twig by Michel Rodriguez.
185              
186             # adds $another_node and $yet_another_node to $node where all are XML:DOM::Elements
187             addElements($node,$another_node,$yet_another_node);
188              
189             or
190              
191             # creates new XML:DOM::Elements and adds them to $node
192             addElements($node,{ name=>'Foo', xlink=> 'cid:..' },{ .. });
193              
194             Returns the modified node
195              
196             Note: The order of attributes is NOT preserved with this method.
197              
198             =cut
199              
200             # based on set_content from XML::DOM::Twig by Michel Rodriguez
201             sub addElements {
202             my $node = shift;
203             my $doc;
204             foreach my $elem (@_) {
205             if ( ref $elem eq 'XML::DOM::Element') {
206             $node->appendChild( $elem);
207             } else {
208             $doc ||= $node->getOwnerDocument;
209             my $element = $doc->createElement($elem->{name});
210             foreach (keys %$elem) {
211             next if /name/;
212             $node->setAttribute($_,$elem->{$_}) if ($_);
213             }
214             $node->appendChild( $element);
215             }
216             }
217             return $node;
218             }
219              
220             =head2 addTextElements
221              
222             Adds Text Elements to a provided XML::DOM::Element.
223              
224             # adds two text nodes to $node
225             addTextElements($node,Foo=>'some text',Bar=>'some more text');
226              
227             Returns the amended node.
228              
229             Preserves the order of the text nodes added.
230              
231             If adding elements with no defined text, these will be added
232             as nodes representing ''
233              
234             =cut
235              
236             sub addTextElements {
237             my $node = shift;
238             my $doc = $node->getOwnerDocument;
239              
240             while (@_) {
241             my $text_elem = $doc->createElement(shift);
242             my $value = shift;
243             $text_elem->appendChild($doc->createTextNode($value)) if (defined $value);
244             $node->appendChild($text_elem);
245             }
246              
247             return $node;
248             }
249              
250             =head2 addText
251              
252             Adds text content to a provided element.
253              
254             addText($node,'This is some text');
255              
256             returns the modified node
257              
258             =cut
259              
260             sub addText {
261             my ($node,$text) = @_;
262             my $doc = $node->getOwnerDocument;
263             $node->appendChild($doc->createTextNode($text));
264             return $node;
265             }
266              
267             =head2 createDocument($root_tag)
268              
269             This function will return a nice XML:DOM::Document object,
270             if called in array context it will return a list of the Document and the root.
271              
272             It requires a root tag, and a list of tags to be added to the document
273              
274             the tags can be scalars :
275              
276             my ($doc,$root) = createDocument('Foo', 'Bar', 'Baz');
277              
278             or a hashref of attributes, and the tags name :
279              
280             my $doc = createDocument({name=>'Foo', xmlns=>'http://www.other.org/namespace', version=>1.3}, 'Bar', 'Baz');
281              
282             NOTE: attributes of tags will not maintain their order
283              
284             =cut
285              
286             sub createDocument {
287             my ($root_tag,@tags) = @_;
288             my $docroot = (ref $root_tag) ? $root_tag->{name} : $root_tag;
289             my $doc = XML::DOM::Document->new();
290             my $root = $doc->createElement($docroot);
291             if (ref $root_tag) {
292             foreach (keys %$root_tag) {
293             next if /name/;
294             $root->setAttribute($_,$root_tag->{$_});
295             }
296             }
297             $doc->appendChild($root);
298              
299             foreach my $tag ( @tags ) {
300             last unless ($tag);
301             my $element_tag = (ref $tag) ? $tag->{name} : $tag;
302             my $element = $doc->createElement ($element_tag);
303             if (ref $tag) {
304             foreach (keys %$tag) {
305             next if /name/;
306             $element->setAttribute($_,$tag->{$_});
307             }
308             }
309             $root->appendChild($element);
310             }
311             return (wantarray) ? ($doc,$root): $doc;
312             }
313              
314             # Based on example in 'Effective XML processing with DOM and XPath in Perl'
315             # by Parand Tony Darugar, IBM Developerworks Oct 1st 2001
316             # Copyright (c) 2001 Parand Tony Darugar
317              
318             =head2 getTextContents($node)
319              
320             returns the text content of a node (and its subnodes)
321              
322             my $content = getTextContents($node);
323              
324             Function by P T Darugar, published in IBM Developerworks Oct 1st 2001
325              
326             =cut
327              
328             sub getTextContents {
329             my ($node, $strip)= @_;
330             my $contents;
331              
332             if (! $node ) {
333             return;
334             }
335             for my $child ($node->getChildNodes()) {
336             if ( $child->getNodeType() == 3 or $child->getNodeType() == 4 ) {
337             $contents .= $child->getData();
338             }
339             }
340              
341             if ($strip) {
342             $contents =~ s/^\s+//;
343             $contents =~ s/\s+$//;
344             }
345              
346             return $contents;
347             }
348              
349              
350             #####################################################
351              
352              
353             1;
354             __END__