File Coverage

blib/lib/XML/Simple/Tree.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package XML::Simple::Tree;
2             ## Aaron Dancygier
3             ## $Id: Tree.pm,v 1.17 2005/11/09 01:21:53 aaron Exp $
4              
5 5     5   13014 use strict;
  5         10  
  5         177  
6              
7 5     5   26 use Carp;
  5         10  
  5         437  
8 5     5   11559 use XML::Simple;
  0            
  0            
9             use Storable qw(dclone);
10             use Class::MethodMaker [
11             scalar => [
12             { '*_get' => 'get_*', '*_set' => '_set_*', }, 'pos',
13             { '*_get' => 'get_*', '*_set' => '_set_*', }, 'level',
14             { '*_get' => 'get_*', '*_set' => '_set_*', }, 'rnode',
15             { '*_get' => 'get_*', '*_set' => '_set_*', }, 'pnode',
16             { '*_get' => 'get_*', '*_set' => '_set_*', }, 'cnode',
17             { '*_get' => 'get_*', '*_set' => '_set_*', }, 'wnode',
18             { '*_get' => 'get_*', '*_set' => '_set_*', }, 'node_key',
19             { '*_get' => 'get_*', '*_set' => '_set_*', }, 'target_key',
20             { '*_get' => 'get_*', '*_set' => '_set_*', }, 'file',
21             { '*_get' => 'get_*', '*_set' => '_set_*', }, 'string'
22             ]
23             ] ;
24              
25             our ($VERSION);
26              
27             $VERSION = '0.03';
28              
29             sub new {
30             my ($class, %data) = @_;
31              
32             my $self = \%data;
33              
34             bless $self, $class;
35              
36             ($self->file_isset() && -e $self->get_file()) ||
37             ($self->string_isset()) ||
38             croak "file or string field must be set\n";
39              
40             $self->_set_rnode(
41             XMLin(
42             ($self->file_isset()) ? $self->get_file() : $self->get_string(),
43             forcearray => 1
44             ) ||
45             croak "can't create XML::Tree::Simple object\n"
46             );
47              
48             ($self->node_key_isset()) ||
49             croak "must specify node key\n";
50              
51             ($self->target_key_isset()) ||
52             croak "must specify target key\n";
53              
54             $self->_set_cnode($self->get_rnode());
55              
56             return $self;
57             }
58              
59             sub find_node {
60             my ($self, $name) = @_;
61              
62             my $cnode = $self->get_cnode();
63             my $target_key = $self->get_target_key(); # ex name
64             my $node_key = $self->get_node_key(); ## ex gallery
65             return undef unless(exists ($cnode->{$node_key}));
66              
67             foreach ($self->children()) {
68             if ($_->{$target_key}[0] eq $name) {
69             # set parent node of wanted node
70             $self->_set_pnode($cnode);
71             $self->_set_wnode($_);
72             last;
73             }
74            
75             unless (exists($_->{$node_key})) {
76             next;
77             }
78            
79             $self->_set_cnode($_);
80              
81             # recurse the next level
82             $self->find_node($name);
83             }
84              
85             ## reset current node to root
86             $self->_set_cnode($self->get_rnode());
87              
88             return $self->get_wnode() || undef;
89             }
90              
91             sub children {
92             my ($self) = @_;
93              
94             my $cnode = $self->get_cnode();
95             my $node_key = $self->get_node_key(); ## ex gallery
96              
97             return undef unless (exists($cnode->{$node_key}));
98              
99             return @{$cnode->{$node_key}};
100             }
101              
102             sub siblings {
103             my ($self) = @_;
104              
105             my $pnode = $self->get_pnode();
106             my $node_key = $self->get_node_key();
107              
108             return undef unless (exists($pnode->{$node_key}));
109              
110             return @{$pnode->{$node_key}};
111             }
112              
113             sub cut_node {
114             my ($self, $name) = @_;
115              
116             $self->find_node($name) || return undef;
117             my $pnode = $self->get_pnode();
118              
119             my $index = 0;
120             my $found = 0;
121            
122             my $target_key = $self->get_target_key();
123             my $node_key = $self->get_node_key();
124              
125             foreach ($self->siblings()) {
126             if ($_->{$target_key}[0] eq $name) {
127             $found = 1;
128             last;
129             }
130             $index ++;
131             }
132             splice(@{$pnode->{$node_key}}, $index, 1) if ($found);
133             }
134              
135             sub move_node {
136             my ($self, $name, $direction) = @_;
137              
138             $self->find_node($name) || return undef;
139             my $pnode = $self->get_pnode();
140              
141             my $index = 0;
142             my $found = 0;
143            
144             my $target_key = $self->get_target_key();
145             my $node_key = $self->get_node_key();
146              
147             foreach ($self->siblings()) {
148             if ($_->{$target_key}[0] eq $name) {
149             $found = 1;
150             last;
151             }
152             $index ++;
153             }
154              
155             my $new_index = 0;
156              
157             if ($direction eq 'up') {
158             $new_index = $index - 1;
159             } elsif ($direction eq 'down') {
160             $new_index =
161             ($index == $#{$pnode->{$node_key}})
162             ? 0
163             : $index + 1
164             ;
165             }
166              
167             my $cloned_node = dclone($pnode->{$node_key}[$new_index]);
168              
169             $pnode->{$node_key}[$new_index] = $pnode->{$node_key}[$index];
170             $pnode->{$node_key}[$index] = $cloned_node;
171             }
172              
173             sub copy_node {
174             my ($self, $name) = @_;
175              
176             return dclone($self->find_node($name));
177             }
178              
179             sub paste_node {
180             my ($self, $want, $paste_node) = @_;
181             my $target_node = $self->find_node($want) || $self->get_rnode();
182              
183             my $node_key = $self->get_node_key();
184             push (@{$target_node->{$node_key}}, $paste_node);
185             }
186              
187             sub traverse {
188             my ($self, $level) = @_;
189             # depth-first pre order traversal
190              
191             $level ||= 0;
192             my $i = 0;
193             my $cnode = $self->get_cnode();
194             my $node_key = $self->get_node_key();
195              
196             return undef unless(exists ($cnode->{$node_key}));
197              
198             foreach ($self->children()) {
199             $self->_set_cnode($_);
200             $self->_set_pnode($cnode);
201             $self->_set_pos($i++);
202              
203             $self->_set_level($level);
204             $self->do_node();
205              
206             if ($self->is_leaf()) {
207             # if last child or outmost level
208             $self->do_leaf();
209             next;
210             }
211              
212             $self->traverse($level + 1);
213             }
214             }
215              
216             sub post_traversal {
217             my ($self, $level) = @_;
218             # depth-first post order traversal
219              
220             $level ||= 0;
221             my $i = 0;
222             my $cnode = $self->get_cnode();
223             my $node_key = $self->get_node_key();
224              
225             return undef unless(exists ($cnode->{$node_key}));
226              
227             foreach ($self->children()) {
228             $self->_set_level($level);
229             $i++;
230             $self->_set_cnode($_);
231             $self->post_traversal($self->get_level() + 1);
232             $self->_set_cnode($_);
233             $self->_set_pnode($cnode);
234             $self->_set_pos($i - 1);
235             $self->do_node();
236              
237             if ($self->is_leaf()) {
238             # if last child or outmost level
239             $self->do_leaf();
240             }
241             $self->_set_level($self->get_level() - 1);
242             }
243             }
244              
245             sub set_do_node {
246             my ($self, $do_node) = @_;
247              
248             $self->{do_node} = $do_node;
249              
250             {
251             local $^W = 0;
252             no strict;
253             *{ ref($self) . '::' . 'do_node' } = $self->{do_node};
254             };
255             }
256              
257             sub set_do_leaf {
258             my ($self, $do_leaf) = @_;
259              
260             $self->{do_leaf} = $do_leaf;
261             {
262             local $^W = 0;
263             no strict;
264             *{ ref($self) . '::' . 'do_leaf' } = $self->{do_leaf};
265             };
266             }
267              
268             sub is_leaf {
269             my $self = shift;
270              
271             my $cnode = $self->get_cnode();
272             my $node_key = $self->get_node_key();
273              
274             return +( ! exists($cnode->{$node_key}) ) ? 1 : 0
275             }
276              
277             ## wrapper function for XMLout.
278             sub toXML {
279             my $self = shift;
280              
281             my $rnode = $self->get_rnode();
282             my $target_key = $self->get_target_key();
283              
284             my $xml;
285              
286             if (ref($_[0]) eq 'HASH') {
287             if (exists($_[0]->{$target_key})) {
288             $xml = XMLout(@_);
289             }
290             } else {
291             $xml = XMLout($rnode, @_);
292             }
293              
294             return $xml;
295             }
296              
297             1;
298              
299             __END__