File Coverage

blib/lib/XML/Smart.pm
Criterion Covered Total %
statement 441 685 64.3
branch 200 334 59.8
condition 82 168 48.8
subroutine 40 73 54.7
pod 43 55 78.1
total 806 1315 61.2


line stmt bran cond sub pod time code
1             #############################################################################
2             ## Name: Smart.pm
3             ## Purpose: XML::Smart
4             ## Author: Graciliano M. P.
5             ## Modified by: Harish Madabushi
6             ## Created: 10/05/2003
7             ## RCS-ID:
8             ## Copyright: (c) 2003 Graciliano M. P.
9             ## Licence: This program is free software; you can redistribute it and/or
10             ## modify it under the same terms as Perl itself
11             #############################################################################
12              
13              
14             package XML::Smart ;
15              
16 11     11   6710524 use 5.006 ;
  11         46  
  11         467  
17              
18 11     11   64 use strict ;
  11         18  
  11         364  
19 11     11   57 use warnings ;
  11         25  
  11         409  
20              
21 11     11   60 use Carp ;
  11         19  
  11         881  
22              
23 11     11   18581 use Object::MultiType ;
  11         67217  
  11         402  
24              
25 11     11   7151 use XML::Smart::Shared qw( _unset_sig_warn _reset_sig_warn ) ;
  11         28  
  11         942  
26              
27 11     11   66 use vars qw(@ISA) ;
  11         14  
  11         623  
28             @ISA = qw(Object::MultiType) ;
29              
30 11     11   7167 use XML::Smart::Tie ;
  11         35  
  11         503  
31 11     11   8140 use XML::Smart::Tree ;
  11         33  
  11         101979  
32              
33              
34             =head1 NAME
35              
36             XML::Smart - A smart, easy and powerful way to access or create XML from fiels, data and URLs.
37              
38             =head1 VERSION
39              
40             Version 1.78
41              
42             =cut
43              
44             our $VERSION = '1.78' ;
45              
46             =head1 SYNOPSIS
47              
48             This module provides an easy way to access/create XML data. It's based on a HASH
49             tree created from the XML data, and enables dynamic access to it through the
50             standard Perl syntax for Hash and Array, without necessarily caring about which
51             you are working with. In other words, B
52             an Array at the same time>!
53              
54             This module additionally provides special resources such as: search for nodes by
55             attribute, select an attribute value in each multiple node, change the returned
56             format, and so on.
57              
58             The module also automatically handles binary data (encoding/decoding to/from base64),
59             CDATA (like contents with ) and Unicode. It can be used to create XML files,
60             load XML from the Web ( just by using an URL as the file path ) and has an easy
61             way to send XML data through sockets - just adding the length of the data in
62             the header.
63              
64             You can use I with L, or with the 2 standard parsers of
65             XML::Smart:
66              
67             =over 10
68              
69             =item I
70              
71             =item I.
72              
73             =back
74              
75             I can be used to load/parse wild/bad XML data, or HTML tags.
76              
77             =head1 Tutorial and F.A.Q.
78              
79             You can find some extra documents about I at:
80              
81             =over 2
82              
83             =item L - Tutorial and examples for XML::Smart.
84              
85             =item L - Frequently Asked Questions about XML::Smart.
86              
87             =back
88              
89             =cut
90              
91             =head1 USAGE
92              
93             ## Create the object and load the file:
94             my $XML = XML::Smart->new('file.xml') ;
95            
96             ## Force the use of the parser 'XML::Smart::Parser'.
97             my $XML = XML::Smart->new('file.xml' , 'XML::Smart::Parser') ;
98            
99             ## Get from the web:
100             my $XML = XML::Smart->new('http://www.perlmonks.org/index.pl?node_id=16046') ;
101              
102             ## Cut the root:
103             $XML = $XML->cut_root ;
104              
105             ## Or change the root:
106             $XML = $XML->{hosts} ;
107              
108             ## Get the address [0] of server [0]:
109             my $srv0_addr0 = $XML->{server}[0]{address}[0] ;
110             ## ...or...
111             my $srv0_addr0 = $XML->{server}{address} ;
112            
113             ## Get the server where the attibute 'type' eq 'suse':
114             my $server = $XML->{server}('type','eq','suse') ;
115            
116             ## Get the address again:
117             my $addr1 = $server->{address}[1] ;
118             ## ...or...
119             my $addr1 = $XML->{server}('type','eq','suse'){address}[1] ;
120            
121             ## Get all the addresses of a server:
122             my @addrs = @{$XML->{server}{address}} ;
123             ## ...or...
124             my @addrs = $XML->{server}{address}('@') ;
125            
126             ## Get a list of types of all the servers:
127             my @types = $XML->{server}('[@]','type') ;
128            
129             ## Add a new server node:
130             my $newsrv = {
131             os => 'Linux' ,
132             type => 'Mandrake' ,
133             version => 8.9 ,
134             address => [qw(192.168.3.201 192.168.3.202)]
135             } ;
136            
137             push(@{$XML->{server}} , $newsrv) ;
138              
139             ## Get/rebuild the XML data:
140             my $xmldata = $XML->data ;
141            
142             ## Save in some file:
143             $XML->save('newfile.xml') ;
144            
145             ## Send through a socket:
146             print $socket $XML->data(length => 1) ; ## show the 'length' in the XML header to the
147             ## socket know the amount of data to read.
148            
149             __DATA__
150            
151            
152            
153            
192.168.0.1
154            
192.168.0.2
155            
156            
157            
192.168.1.10
158            
192.168.1.20
159            
160            
161            
162              
163             =cut
164              
165             ###############
166             # AUTOLOADERS #
167             ###############
168              
169             ## Lead to mem leak? ##
170              
171             sub data {
172 7     7 1 6563 require XML::Smart::Data ;
173 7         61 _unset_sig_warn() ;
174 7         137 *data = \&XML::Smart::Data::data ;
175 7         41 _reset_sig_warn() ;
176 7         144 &XML::Smart::Data::data(@_) ;
177             }
178              
179             sub apply_dtd {
180 3     3 1 26 require XML::Smart::DTD ;
181 3         15 _unset_sig_warn() ;
182 3         33 *apply_dtd = \&XML::Smart::DTD::apply_dtd ;
183 3         14 _reset_sig_warn() ;
184 3         22 &XML::Smart::DTD::apply_dtd(@_) ;
185             }
186              
187 0     0 1 0 sub xpath { _load_xpath() ; &XML::Smart::XPath::xpath(@_) ;}
  0         0  
188 0     0 1 0 sub XPath { _load_xpath() ; &XML::Smart::XPath::XPath(@_) ;}
  0         0  
189 0     0 1 0 sub xpath_pointer { _load_xpath() ; &XML::Smart::XPath::xpath_pointer(@_) ;}
  0         0  
190 0     0 1 0 sub XPath_pointer { _load_xpath() ; &XML::Smart::XPath::XPath_pointer(@_) ;}
  0         0  
191              
192             sub _load_xpath {
193              
194 0     0   0 require XML::Smart::XPath ;
195 0         0 _unset_sig_warn() ;
196 0         0 *xpath = \&XML::Smart::XPath::xpath ;
197 0         0 *XPath = \&XML::Smart::XPath::XPath ;
198 0         0 *xpath_pointer = \&XML::Smart::XPath::xpath_pointer ;
199 0         0 *XPath_pointer = \&XML::Smart::XPath::XPath_pointer ;
200 0     0   0 *_load_xpath = sub {} ;
  0         0  
201 0         0 _reset_sig_warn() ;
202              
203             }
204              
205             #################
206             # NO_XML_PARSER #
207             #################
208              
209             sub NO_XML_PARSER {
210 0 0   0 0 0 $XML::Smart::Tree::NO_XML_PARSER = !@_ ? 1 : ( $_[0] ? 1 : undef ) ;
    0          
211             }
212              
213             #######
214             # NEW #
215             #######
216              
217             sub new {
218              
219 273     273 1 249311 my $class = shift ;
220 273         544 my $file = shift ;
221 273 100 100     2769 my $parser = ($_[0] and $_[0] !~ /^(?:uper|low|arg|on|no|use)\w+$/i) ? shift(@_) : '' ;
222            
223 273         2358 my $this = Object::MultiType->new(
224             boolsub => \&boolean ,
225             scalarsub => \&content ,
226             tiearray => 'XML::Smart::Tie::Array' ,
227             tiehash => 'XML::Smart::Tie::Hash' ,
228             tieonuse => 1 ,
229             code => \&find_arg ,
230             ) ;
231              
232              
233 273         24263 $$this->{ parser } = $parser ;
234              
235 273         2141 $parser = &XML::Smart::Tree::load($parser) ;
236              
237 273 100 66     1696 if ( !($file) or $file eq '') { $$this->{tree} = {} ;}
  88         351  
238             else {
239 185         280 eval {
240 185         774 $$this->{tree} = &XML::Smart::Tree::parse($file,$parser,@_) ;
241 185 50       597 }; croak( $@ ) if( $@ );
242             }
243            
244 273         982 $$this->{point} = $$this->{tree} ;
245 273         860 bless($this,$class) ;
246              
247 273         921 return $this ;
248              
249             }
250              
251             #########
252             # CLONE #
253             #########
254              
255             sub clone {
256            
257 1502     1502 0 1759 my $saver = shift ;
258            
259 1502         1655 my ($pointer , $back , $array , $key , $i , $null_clone) ;
260            
261 1502 100 66     4390 if ($#_ == 0 && !ref $_[0]) {
262 147         283 my $nullkey = shift ;
263 147         270 $pointer = {} ;
264 147         245 $back = {} ;
265 147         217 $null_clone = 1 ;
266            
267 147         352 ($i) = ( $nullkey =~ /(?:^|\/)\/\[(\d+)\]$/s );
268 147         1050 ($key) = ( $nullkey =~ /(.*?)(?:\/\/\[\d+\])?$/s );
269 147 100       538 if ($key =~ /^\/\[\d+\]$/) { $key = undef ;}
  3         8  
270             }
271            
272             else {
273 1355         1586 $pointer = shift ;
274 1355         1362 $back = shift ;
275 1355         1524 $array = shift ;
276 1355         1685 $key = shift ;
277 1355         1634 $i = shift ;
278             }
279            
280 1502         6496 my $clone = Object::MultiType->new(
281             boolsub => \&boolean ,
282             scalarsub => \&content ,
283             tiearray => 'XML::Smart::Tie::Array' ,
284             tiehash => 'XML::Smart::Tie::Hash' ,
285             tieonuse => 1 ,
286             code => \&find_arg ,
287             ) ;
288 1502         84897 bless($clone,__PACKAGE__) ;
289            
290 1502 100       3777 if ( !$saver->is_saver ) { $saver = $$saver ;}
  90         391  
291            
292 1502 100       6368 if (!$back) {
293 1265 50       2442 if (!$pointer) { $back = $saver->{back} ;}
  0         0  
294 1265         2105 else { $back = $saver->{point} ;}
295             }
296            
297 1502 50 66     9001 if (!$array && !$pointer) { $array = $saver->{array} ;}
  0         0  
298            
299 1502         1676 my @keyprev ;
300            
301 1502 100       2966 if (defined $key) { @keyprev = $key ;}
  1223 50       3826  
302 279         763 elsif (defined $i) { @keyprev = "[$i]" ;}
303            
304 1502 100       2693 if (!defined $key) { $key = $saver->{key} ;}
  279         484  
305 1502 100       2915 if (!defined $i) { $i = $saver->{i} ;}
  992         1561  
306            
307 1502 50       2968 if (!$pointer) { $pointer = $saver->{point} ;}
  0         0  
308            
309             # my @call = caller ;
310             # print STDERR "CLONE>> $key , $i >> @{$saver->{keyprev}} >> @_\n" ;
311              
312              
313 1502         4525 $$clone->{tree} = $saver->{tree} ;
314 1502         2567 $$clone->{point} = $pointer ;
315 1502         2278 $$clone->{back} = $back ;
316 1502         2319 $$clone->{array} = $array ;
317 1502         2604 $$clone->{key} = $key ;
318 1502         2549 $$clone->{i} = $i ;
319            
320 1502 50       3188 if ( @keyprev ) {
321 1502 100       3285 $$clone->{keyprev} = ( $saver->{keyprev} ) ? [@{$saver->{keyprev}}] : [] ;
  1078         3639  
322 1502         1907 push(@{$$clone->{keyprev}} , @keyprev) ;
  1502         3795  
323             }
324            
325 1502 100       3301 if (defined $_[0]) { $$clone->{content} = \$_[0] ;}
  309         862  
326            
327 1502 100 66     7497 if ( $null_clone || $saver->{null} ) {
328 147         332 $$clone->{null} = 1 ;
329             ## $$clone->{self} = $clone ;
330             }
331            
332 1502 50       2946 $$clone->{XPATH} = $saver->{XPATH} if $saver->{XPATH} ;
333            
334 1502         8222 return( $clone ) ;
335              
336             }
337              
338             ###########
339             # BOOLEAN #
340             ###########
341              
342             sub boolean {
343              
344 3839     3839 0 37100 my $this = shift ;
345            
346 3839 100       12117 if ( $this->null ) {
347 204         1085 return 0 ;
348             } else {
349 3635         18919 return 1 ;
350             }
351            
352             }
353              
354             ########
355             # NULL #
356             ########
357              
358             sub null {
359              
360 4222     4222 1 4527 my $this = shift ;
361              
362 4222 100       9529 if( $$this->{null} ) {
363 164         402 return 1 ;
364             }
365            
366 4058 100       4171 if( (keys %{$$this->{tree}}) < 1 ) {
  4058         11100  
367 52         136 return 1 ;
368             }
369            
370 4006         8377 return ;
371              
372             }
373              
374             ########
375             # BASE #
376             ########
377              
378             sub base {
379              
380 98     98 1 194 my $this = shift ;
381            
382 98         513 my $base = Object::MultiType->new(
383             boolsub => \&boolean ,
384             scalarsub => \&content ,
385             tiearray => 'XML::Smart::Tie::Array' ,
386             tiehash => 'XML::Smart::Tie::Hash' ,
387             tieonuse => 1 ,
388             code => \&find_arg ,
389             ) ;
390            
391 98         6099 bless($base,__PACKAGE__) ;
392            
393 98         260 $$base->{tree} = $this->tree ;
394 98         241 $$base->{point} = $$base->{tree} ;
395            
396 98         170 return( $base ) ;
397              
398             }
399              
400             ########
401             # BACK #
402             ########
403              
404             sub back {
405              
406 171     171 1 551 my $this = shift ;
407            
408 171         232 my @tree ;
409 171 100       543 if( $$this->{keyprev} ) {
410 98         140 @tree = @{$$this->{keyprev}} ;
  98         333  
411             }
412            
413 171 100       475 if( !@tree ) {
414 73         356 return $this ;
415             }
416            
417 98         171 my $last = pop(@tree) ;
418 98         264 my $i = 0 ;
419 98 100       295 if( $last =~ /^\[(\d+)\]$/ ) {
420 12         31 $i = $1 ;
421 12         21 $last = pop(@tree) ;
422             }
423            
424 98         246 my $back = $this->base ;
425            
426 98         450 foreach my $tree_i ( @tree ) {
427 144 100       1859 if ($tree_i =~ /^\[(\d+)\]$/) {
428 21         50 my $i = $1 ;
429 21         58 $back = $back->[$i] ;
430             } else {
431 123         317 $back = $back->{$tree_i} ;
432             }
433             }
434            
435 98 100       3425 if ( wantarray ) {
436 11         44 return( $back , $last , $i ) ;
437             }
438              
439 87         259 return( $back ) ;
440              
441             }
442              
443             ########
444             # PATH #
445             ########
446              
447             sub path {
448              
449 18     18 1 538 my $this = shift ;
450 18         28 my @tree = @{$$this->{keyprev}} ;
  18         149  
451              
452 18         25 my $path ;
453            
454 18         39 foreach my $tree_i ( @tree ) {
455 78 100       248 $path .= '/' if $tree_i !~ /^\[\d+\]$/ ;
456 78         114 $path .= $tree_i ;
457             }
458            
459 18         115 return $path ;
460              
461             }
462              
463             #################
464             # PATH_AS_XPATH #
465             #################
466              
467             sub path_as_xpath {
468              
469 9     9 1 21 my $this = shift ;
470 9         20 my @tree = @{$$this->{keyprev}} ;
  9         51  
471            
472 9         18 my $path ;
473            
474 9         15 foreach my $tree_i ( @tree ) {
475 42 100       117 if ( $tree_i =~ /^\[(\d+)\]$/ ) {
476 15         37 my $i = $1 + 1 ;
477 15         41 $path .= "[$i]" ;
478             } else {
479 27         58 $path .= "/$tree_i" ;
480             }
481             }
482            
483 9         36 $path =~ s/\[1\]$// ;
484            
485 9         39 my $t = $this->is_node ;
486            
487 9 100       257 if ( !$this->is_node ) {
488 6         272 $path =~ s/\/([^\/]+)$/\/\@$1/s ;
489             }
490            
491 9         123 return $path ;
492              
493             }
494              
495             ########
496             # ROOT #
497             ########
498              
499             sub root {
500              
501 0     0 1 0 my $this = shift ;
502            
503 0         0 my $root = ( $this->base->nodes_keys )[0] ;
504            
505 0         0 return $root ;
506              
507             }
508              
509             #######
510             # KEY #
511             #######
512              
513             sub key {
514              
515 78     78 1 112 my $this = shift ;
516 78         99 my $k = @{$$this->{keyprev}}[ $#{$$this->{keyprev}} ] ;
  78         185  
  78         169  
517 78 100       273 if ($k =~ /^\[(\d+)\]$/) {
518 12         20 $k = @{$$this->{keyprev}}[ $#{$$this->{keyprev}} -1 ] ;
  12         29  
  12         31  
519             }
520            
521 78         204 return $k ;
522              
523             }
524              
525             #####
526             # I #
527             #####
528              
529             sub i {
530              
531 0     0 1 0 my $this = shift ;
532 0         0 my $i = $$this->{i} ;
533              
534 0         0 return $i ;
535             }
536              
537             ########
538             # COPY #
539             ########
540              
541             sub copy {
542              
543 78     78 1 1378 my $this = shift ;
544              
545 78         404 my $data = $this->data( noheader => 1 ) ;
546 78         468 my $copy = XML::Smart->new( $data, $$this->{ parser } ) ;
547              
548              
549 78 100       351 if( $$this->{keyprev} ) {
550 5         13 my @old_array = @{ $$this->{keyprev} } ;
  5         20  
551 5         15 my @new_array = @old_array ;
552 5         18 $$copy->{keyprev} = \@new_array ;
553             }
554            
555 78         357 my ( $back , $key , $i ) = $copy->back ;
556            
557 78         298 _unset_sig_warn() ;
558 78 100       855 if( $key ne '' ) {
559 5         23 $copy = $back->{$key} ;
560 5 50       20 $copy = $back->[$i] if $i ;
561             }
562 78         489 _reset_sig_warn() ;
563              
564 78         419 return $copy ;
565              
566             }
567              
568             ##############
569             # _COPY_HASH #
570             ##############
571              
572             sub _copy_hash {
573              
574 0     0   0 my ( $ref ) = @_ ;
575 0         0 my $copy ;
576            
577 0 0       0 if( ref $ref eq 'HASH' ) {
    0          
    0          
578 0         0 $copy = {} ;
579 0         0 foreach my $Key ( keys %$ref ) {
580 0 0       0 if( ref $$ref{$Key} ) {
581 0         0 $$copy{$Key} =&_copy_hash($$ref{$Key}) ;
582             } else {
583 0         0 $$copy{$Key} = $$ref{$Key} ;
584             }
585             }
586             } elsif( ref $ref eq 'ARRAY' ) {
587 0         0 $copy = [] ;
588 0         0 foreach my $i ( @$ref ) {
589 0 0       0 if( ref $i ) {
590 0         0 push( @$copy, &_copy_hash($i) ) ;
591             } else {
592 0         0 push( @$copy, $i ) ;
593             }
594             }
595             } elsif( ref $ref eq 'SCALAR' ) {
596 0         0 my $copy = $$ref ;
597 0         0 return( \$copy ) ;
598             } else {
599 0         0 return( {} ) ;
600             }
601            
602 0         0 return( $copy ) ;
603            
604             }
605              
606             ###########
607             # TREE_OK #
608             ###########
609              
610             sub tree_ok {
611 0     0 1 0 return _tree_ok_parse( &tree ) ;
612             }
613              
614             ##############
615             # POINTER_OK #
616             ##############
617              
618             sub pointer_ok {
619 0     0 1 0 return _tree_ok_parse( &pointer ) ;
620             }
621              
622             sub tree_pointer_ok {
623 0     0 1 0 &pointer_ok ;
624             }
625              
626             ##################
627             # _TREE_OK_PARSE #
628             ##################
629              
630             sub _tree_ok_parse {
631              
632 0     0   0 my ( $ref ) = @_ ;
633 0         0 my $copy ;
634            
635 0 0       0 if( ref $ref eq 'HASH' ) {
    0          
    0          
636 0         0 $copy = {} ;
637 0         0 foreach my $Key ( keys %$ref ) {
638 0 0 0     0 next if $Key eq '/order' || $Key eq '/nodes' || $Key =~ /\/\.CONTENT\// ;
      0        
639 0 0       0 if( ref $$ref{$Key} ) {
640 0         0 $$copy{$Key} =&_tree_ok_parse($$ref{$Key}) ;
641             } else {
642 0         0 $$copy{$Key} = $$ref{$Key} ;
643             }
644             }
645             } elsif( ref $ref eq 'ARRAY' ) {
646 0         0 $copy = [] ;
647 0         0 foreach my $i ( @$ref ) {
648 0 0       0 if( ref $i ) {
649 0         0 push( @$copy, &_tree_ok_parse($i) ) ;
650             } else {
651 0         0 push( @$copy, $i ) ;
652             }
653             }
654             } elsif( ref $ref eq 'SCALAR' ) {
655 0         0 my $copy = $$ref ;
656 0         0 return( \$copy ) ;
657             } else {
658 0         0 return( {} ) ;
659             }
660            
661 0         0 return( $copy ) ;
662              
663             }
664              
665             ########
666             # TREE #
667             ########
668              
669             sub tree {
670              
671 440     440 1 2000 my $hash_to_return = ${$_[0]}->{tree} ;
  440         1887  
672            
673 440         6665 return ( $hash_to_return ) ;
674            
675             }
676              
677             sub tree_pointer {
678 0     0 1 0 &pointer ;
679             }
680              
681             #############
682             # DUMP_TREE #
683             #############
684              
685             sub dump_tree {
686 0     0 1 0 require Data::Dumper ;
687 0         0 local $Data::Dumper::Sortkeys = 1 ;
688 0         0 return Data::Dumper::Dumper( &tree ) ;
689             }
690              
691             sub dump_tree_ok {
692 0     0 0 0 require Data::Dumper ;
693 0         0 local $Data::Dumper::Sortkeys = 1 ;
694 0         0 return Data::Dumper::Dumper( &tree_ok ) ;
695             }
696              
697              
698             ################
699             # DUMP_POINTER #
700             ################
701              
702             sub dump_pointer {
703 0     0 1 0 require Data::Dumper ;
704 0         0 local $Data::Dumper::Sortkeys = 1 ;
705 0         0 return Data::Dumper::Dumper( &pointer ) ;
706             }
707              
708             sub dump_pointer_ok {
709 0     0 0 0 require Data::Dumper ;
710 0         0 local $Data::Dumper::Sortkeys = 1 ;
711 0         0 return Data::Dumper::Dumper( &pointer_ok ) ;
712             }
713              
714              
715             sub dump_tree_pointer {
716 0     0 1 0 &dump_pointer ;
717             }
718              
719             sub dump_tree_pointer_ok {
720 0     0 0 0 &dump_pointer_ok ;
721             }
722              
723             ###########
724             # POINTER #
725             ###########
726              
727             sub pointer {
728            
729 115     115 1 171 my $hash_to_return ;
730            
731 115 100       162 if ( ${$_[0]}->{content} ) {
  115         380  
732 9         15 $hash_to_return = ${${$_[0]}->{content}} ;
  9         14  
  9         24  
733             } else {
734 106         146 $hash_to_return = ${$_[0]}->{point} ;
  106         248  
735             }
736            
737 115         303 return ( $hash_to_return ) ;
738             }
739              
740             ############
741             # CUT_ROOT #
742             ############
743              
744             sub cut_root {
745              
746 6     6 1 214 my $this = shift ;
747            
748 6         31 my @nodes = $this->nodes_keys ;
749            
750 6 50       22 if( $#nodes > 0 ) {
751 0         0 return $this ;
752             }
753            
754 6         11 my $root = $nodes[0] ;
755 6         16 return( $this->{$root} ) ;
756              
757             }
758              
759             ###########
760             # IS_NODE #
761             ###########
762              
763             sub is_node {
764              
765 21     21 1 158 my $this = shift ;
766              
767 21 50       49 return if $this->null ;
768            
769 21         64 my $key = $this->key ;
770 21         62 my $back = $this->back ;
771            
772 21 100 66     73 return 1 if( $back->{'/nodes'}{$key} || $back->{$key}->nodes_keys ) ;
773 12         44 return undef ;
774            
775             }
776              
777             ########
778             # ARGS #
779             ########
780              
781             sub args {
782              
783 0     0 1 0 my $this = shift ;
784              
785 0 0       0 return () if $this->null ;
786            
787 0         0 my @args ;
788            
789 0         0 my $nodes = $this->back->{'/nodes'} ;
790 0         0 my $pointer = $$this->{point} ;
791            
792 0         0 foreach my $Key ( keys %$this ) {
793              
794 0 0       0 next if( $$nodes{$Key} ) ;
795              
796 0 0 0     0 if(
      0        
      0        
797 0         0 ( !ref $$pointer{ $Key} ) ||
798             ( ref( $$pointer{ $Key} ) eq 'HASH') ||
799             ( ref( $$pointer{ $Key} ) eq 'ARRAY' && $#{$$pointer{$Key}} == 0 )
800             ) {
801            
802 0         0 push(@args , $Key) ;
803            
804             }
805             }
806            
807 0         0 return @args ;
808             }
809              
810             ###############
811             # ARGS_VALUES #
812             ###############
813              
814             sub args_values {
815              
816 0     0 1 0 my $this = shift ;
817            
818 0 0       0 return () if $this->null ;
819            
820 0         0 my @args = $this->args ;
821            
822 0         0 my @values ;
823            
824 0         0 foreach my $args_i ( @args ) {
825 0         0 push( @values, $this->{$args_i} ) ;
826             }
827            
828 0         0 return @values ;
829            
830             }
831              
832             #########
833             # NODES #
834             #########
835              
836             sub nodes {
837              
838 3     3 1 8 my $this = shift ;
839            
840 3 50       12 return () if $this->null ;
841            
842 3         10 my $nodes = $this->{'/nodes'}->pointer ;
843 3         14 my $pointer = $$this->{point} ;
844            
845 3         152 my @nodes ;
846            
847 3         8 foreach my $Key ( keys %$this ) {
848              
849 9 50 66     72 if(
      33        
      66        
850 0         0 $$nodes{$Key} ||
851             (ref($$pointer{$Key}) eq 'HASH') ||
852             (ref($$pointer{$Key}) eq 'ARRAY' && $#{$$pointer{$Key}} > 0)
853             ) {
854              
855 3 50       15 if( ref($$pointer{$Key}) eq 'ARRAY' ) {
856 0         0 my $n = $#{$$pointer{$Key}} ;
  0         0  
857 0         0 for my $i (0..$n) {
858 0         0 push( @nodes, $this->{$Key}[$i] ) ;
859             }
860             } else {
861 3         10 push( @nodes, $this->{$Key}[0] ) ;
862             }
863             }
864             }
865            
866 3         102 return @nodes ;
867              
868             }
869              
870             ##############
871             # NODES_KEYS #
872             ##############
873              
874             sub nodes_keys {
875              
876 25     25 1 126 my $this = shift ;
877            
878 25 50       72 return () if $this->null ;
879            
880            
881 25         87 my $nodes = $this->{'/nodes'}->pointer ;
882 25         86 my $pointer = $$this->{point} ;
883            
884 25         676 my @nodes ;
885 25         73 foreach my $Key ( keys %$this ) {
886 19 50 66     109 if(
      33        
      66        
887 0         0 $$nodes{$Key} ||
888             (ref($$pointer{$Key}) eq 'HASH') ||
889             (ref($$pointer{$Key}) eq 'ARRAY' && $#{$$pointer{$Key}} > 0)
890             ) {
891 13         33 push(@nodes , $Key) ;
892             }
893             }
894            
895 25         148 return @nodes ;
896             }
897              
898             ############
899             # SET_NODE #
900             ############
901              
902             sub set_node {
903              
904 18     18 1 41 my $this = shift ;
905 18         44 my ( $bool ) = @_ ;
906            
907 18 100       54 if( !@_ ) {
908 3         6 $bool = 1 ;
909             }
910            
911 18         250 my $key = $this->key ;
912 18         57 my $back = $this->back ;
913            
914 18 100       60 $back->{'/nodes'} = {} if( $back->{'/nodes'}->null ) ;
915 18         61 my $nodes = $back->{'/nodes'}->pointer ;
916            
917 18 100       54 if( $bool ) {
918              
919 12 100 66     620 if( $$nodes{$key} && $$nodes{$key} =~ /^(\w+,\d+),(\d*)/ ) {
920 3         16 $$nodes{$key} = "$1,1" ;
921             } else {
922 9         25 $$nodes{$key} = 1 ;
923             }
924            
925 12 100       32 if ( !$this->{CONTENT} ) {
926 9         48 my $content = $this->content ;
927 9 50       45 $this->{CONTENT} = $content if $content ne '' ;
928             }
929              
930             } else {
931            
932 6         179 delete $$nodes{$key} ;
933 6         17 my @keys = keys %$this ;
934 6 50 33     46 if( $#keys == 0 && $keys[0] eq 'CONTENT' ) {
935 6 50       19 my $content = ( !$this->{CONTENT}->null ) ? $this->{CONTENT}('.') : $this->content ;
936 6         46 $this->back->pointer->{$key} = $content ;
937             }
938             }
939            
940             }
941              
942             ###########
943             # SET_TAG #
944             ###########
945              
946             sub set_tag {
947 0     0 1 0 &set_node ;
948             }
949              
950             #############
951             # SET_ORDER #
952             #############
953              
954             sub set_order {
955 6     6 1 12 my $this = shift ;
956 6         15 my $pointer = $$this->{point} ;
957 6         12 @{$$pointer{'/order'}} = @_ ;
  6         112  
958             }
959              
960             sub order {
961 6     6 1 10 my $this = shift ;
962 6         14 my $pointer = $$this->{point} ;
963 6 50 33     40 return @{$$pointer{'/order'}} if defined $$pointer{'/order'} && ref($$pointer{'/order'}) eq 'ARRAY' ;
  6         33  
964 0         0 return() ;
965             }
966              
967             #############
968             # SET_CDATA #
969             #############
970              
971             sub set_node_type {
972              
973 33     33 0 55 my $this = shift ;
974              
975 33         56 my ( $type, $bool ) = @_ ;
976 33 50       86 if( $#_ < 1 ) {
977 0         0 $bool = 1 ;
978             }
979            
980 33         103 my $key = $this->key ;
981 33         93 my $back = $this->back ;
982            
983 33 50       94 $back->{'/nodes'} = {} if( $back->{'/nodes'}->null );
984 33         90 my $nodes = $back->{'/nodes'}->pointer ;
985            
986 33 100       108 if( $bool ) {
987              
988 15 100 66     528 if( $$nodes{$key} && $$nodes{$key} =~ /^\w+,\d+,(\d*)/ ) {
989 9         21 my $val = $1 ;
990 9         31 $$nodes{$key} = "$type,1,$val" ;
991             } else {
992 6 50       22 my $existing_node_data = ( $$nodes{$key} ) ? $$nodes{$key} : "" ;
993 6         32 $$nodes{$key} = "$type,1," . $existing_node_data ;
994             }
995            
996 15 100       39 if( !$this->{CONTENT} ) {
997 11         37 my $content = $this->content ;
998 11 50       51 $this->{CONTENT} = $content if $content ne '' ;
999             }
1000              
1001             } else {
1002              
1003 18 100       762 if( !$$nodes{$key} ) {
    100          
    50          
    0          
1004 7         25 my $tp = _data_type( $back->{$key} ) ;
1005 7 50       26 if ( $tp > 2 ) { $$nodes{$key} = "$type,0," ;}
  7         226  
1006             } elsif( $$nodes{$key} eq '1' ) {
1007 5         24 $$nodes{$key} = "$type,0,1" ;
1008             } elsif( $$nodes{$key} =~ /^\w+,\d+,1/ ) {
1009 6         32 $$nodes{$key} = "$type,0,1" ;
1010             } elsif( $$nodes{$key} =~ /^\w+,\d+,0?$/ ) {
1011              
1012 0         0 delete $$nodes{$key} ;
1013 0         0 my @keys = keys %$this ;
1014              
1015 0 0 0     0 if( $#keys == 0 && $keys[0] eq 'CONTENT') {
1016 0         0 my $content = $this->{CONTENT}('.') ;
1017 0         0 $this->back->pointer->{$key} = $content ;
1018             }
1019              
1020             }
1021             }
1022            
1023             }
1024              
1025             #############
1026             # SET_CDATA #
1027             #############
1028              
1029             sub set_cdata {
1030 15     15 1 37 my $this = shift ;
1031 15         61 $this->set_node_type('cdata',@_) ;
1032             }
1033              
1034             ##############
1035             # SET_BINARY #
1036             ##############
1037              
1038             sub set_binary {
1039 18     18 1 32 my $this = shift ;
1040 18         59 $this->set_node_type('binary',@_) ;
1041             }
1042              
1043             #################
1044             # SET_AUTO_NODE #
1045             #################
1046              
1047             sub set_auto_node {
1048              
1049 3     3 1 9 my $this = shift ;
1050            
1051 3         12 my $key = $this->key ;
1052 3         13 my $back = $this->back ;
1053            
1054 3 50       12 $back->{'/nodes'} = {} if( $back->{'/nodes'}->null );
1055 3         12 my $nodes = $back->{'/nodes'}->pointer ;
1056            
1057 3 50 33     11 if( !$$nodes{$key} || $$nodes{$key} eq '1' ) {
    50          
    0          
1058             # Do nothing. ;
1059             } elsif( $$nodes{$key} =~ /^\w+,\d+,1/ ) {
1060 3         128 $$nodes{$key} = 1 ;
1061             } elsif( $$nodes{$key} =~ /^\w+,\d+,0?$/ ) {
1062              
1063 0         0 delete $$nodes{$key} ;
1064 0         0 my @keys = keys %$this ;
1065              
1066 0 0 0     0 if( $#keys == 0 && $keys[0] eq 'CONTENT') {
1067 0         0 my $content = $this->{CONTENT}('.') ;
1068 0         0 $this->back->pointer->{$key} = $content ;
1069             }
1070              
1071             }
1072              
1073             }
1074              
1075             ############
1076             # SET_AUTO #
1077             ############
1078              
1079             sub set_auto {
1080            
1081 3     3 1 9 my $this = shift ;
1082            
1083 3         13 my $key = $this->key ;
1084 3         15 my $back = $this->back ;
1085            
1086 3 50       13 $back->{'/nodes'} = {} if $back->{'/nodes'}->null ;
1087 3         12 my $nodes = $back->{'/nodes'}->pointer ;
1088            
1089 3         12 delete $$nodes{$key} ;
1090 3         100 my @keys = keys %$this ;
1091 3 50 33     30 if( $#keys == 0 && $keys[0] eq 'CONTENT') {
1092 3         12 my $content = $this->{CONTENT}('.') ;
1093 3         23 $this->back->pointer->{$key} = $content ;
1094             }
1095              
1096             }
1097              
1098             ##############
1099             # _DATA_TYPE #
1100             ##############
1101              
1102             ## 4 binary
1103             ## 3 CDATA
1104             ## 2 content
1105             ## 1 value
1106              
1107             sub _data_type {
1108              
1109              
1110 1231     1231   78163 my $data = shift ;
1111              
1112             # TODO: 0x80, 0x81, 0x8d, 0x8f, 0x90, 0xa0
1113 1231         12553 my @bin_data = (
1114             0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8e, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
1115             0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9e, 0x9f, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
1116             0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc,
1117             0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce,
1118             0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0,
1119             0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2,
1120             0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x20,
1121             );
1122              
1123              
1124 1231         108006 my $bin_string = join( '', ( map( pack("H*", $_), @bin_data ) ) ) ;
1125            
1126 1231 100 100     25959 return 4 if( $data && (
      66        
1127             $data =~ /[^\w\d\s!"#\$\%&'\(\)\*\+,\-\.\/:;<=>\?\@\[\\\]\^\`\{\|}~~$bin_string]/s
1128             or
1129             $data =~ /(\240|\351|\361|\363|\341|\374|\340|\350|\366|\343|\355|\366|\344|\372|\364|\324|\301|\342)/s
1130             )
1131             ) ;
1132 1070 100 100     4947 return 3 if( $data && $data =~ /<.*?>/s ) ;
1133 1048 100 100     4674 return 2 if( $data && $data =~ /[\r\n\t]/s ) ;
1134 1019         11866 return 1 ;
1135             }
1136              
1137             #######
1138             # RET #
1139             #######
1140              
1141             sub ret {
1142              
1143 27     27 0 38 my $this = shift ;
1144 27         47 my $type = shift ;
1145            
1146 27 50       80 if ($type =~ /^\s*\s*$/si ) {
1147 0         0 return $this->data_pointer( noheader => 1 ) ;
1148             }
1149            
1150 27         42 my @ret ;
1151 27         89 $type =~ s/[^<\$\@\%\.k]//gs ;
1152            
1153 27 100       96 if ($type =~ /^
1154 6         22 $type =~ s/^<+// ;
1155            
1156 6         22 my ($back , $key , $i) = $this->back ;
1157            
1158 6 50       41 if( $type =~ /\$$/ ) {
    50          
    0          
1159 0         0 @ret = $back->{$key}[$i]->content ;
1160             } elsif( $type =~ /\@$/ ) {
1161              
1162 6         9 @ret = @{$back} ;
  6         21  
1163              
1164 6         25 foreach my $ret_i ( @ret ) {
1165 24         787 $ret_i = $ret_i->{$key}[$i] ;
1166             }
1167            
1168             } elsif( $type =~ /\%$/ ) {
1169 0         0 @ret = %{$back->{$key}[$i]} ;
  0         0  
1170             }
1171             } else {
1172              
1173 21 100       67 if( $this->null ) {
1174 3         13 return ;
1175             }
1176            
1177 18 50       181 if ($type =~ /\$$/) { @ret = $this->content ; }
  0 100       0  
    50          
    100          
    50          
1178 6         10 elsif ($type =~ /\@$/) { @ret = @{$this} ; }
  6         25  
1179 0         0 elsif ($type =~ /\%$/) { @ret = %{$this} ; }
  0         0  
1180 9         29 elsif ($type =~ /\.$/) { @ret = $this->pointer ; }
1181             elsif ($type =~ /[\@\%]k$/) {
1182              
1183 3         6 my @keys = keys %{$this} ;
  3         10  
1184              
1185 3         16 foreach my $key ( @keys ) {
1186 9         15 my $n = $#{ $this->{$key} } ;
  9         24  
1187 9 50       30 if ($n > 0) {
1188 0         0 my @multi = ($key) x ($n+1) ;
1189 0         0 push(@ret , @multi) ;
1190             } else {
1191 9         341 push(@ret , $key) ;
1192             }
1193             }
1194              
1195             }
1196             }
1197            
1198 24 50       239 if( $type =~ /^\$./ ) {
1199 0         0 foreach my $ret_i ( @ret ) {
1200 0 0       0 if(ref($ret_i) eq 'XML::Smart') {
1201 0         0 $ret_i = $ret_i->content ;
1202             }
1203             }
1204             }
1205            
1206              
1207 24 100       58 if( wantarray ) {
1208 15         67 return( @ret ) ;
1209             }
1210 9         35 return $ret[0] ;
1211              
1212             }
1213              
1214             ########
1215             # FIND #
1216             ########
1217              
1218             sub find {
1219 0     0 0 0 &find_arg
1220             }
1221              
1222             ############
1223             # FIND_ARG #
1224             ############
1225              
1226             sub find_arg {
1227              
1228 102     102 0 2507 my $this = shift ;
1229 102 100 66     483 if( $#_ == 0 && ref($_[0]) ne 'ARRAY' ) {
1230 27         111 return $this->ret(@_) ;
1231             }
1232            
1233 75 100 100     258 if( $#_ == 1 && $_[0] eq '[@]' ) {
1234 3         8 my $arg = $_[1] ;
1235 3         14 return $this->{$arg}('<@') ;
1236             }
1237            
1238 72         101 my @search ;
1239            
1240 72         208 for( my $i = 0; $i <= $#_ ; ++$i ) {
1241 75 100 33     678 if( ref($_[$i]) eq 'ARRAY' ) {
    50 33        
1242 6         19 push(@search , $_[$i]) ;
1243             } elsif( ref($_[$i]) ne 'ARRAY' && ref($_[$i+1]) ne 'ARRAY' && ref($_[$i+2]) ne 'ARRAY' ) {
1244 69         224 push(@search , [$_[$i] , $_[$i+1] , $_[$i+2]]) ;
1245 69         209 $i += 2 ;
1246             }
1247             }
1248            
1249             #use Data::Dumper ; print Dumper(\@search);
1250             #print "*** @search\n" ;
1251            
1252 72 50       164 if ( !@search ) {
1253 0         0 return ;
1254             }
1255            
1256 72         153 my $key = $$this->{key} ;
1257            
1258 72         98 my @hashes ;
1259            
1260 72 100       314 if( ref($$this->{array}) ) {
1261 69         76 push( @hashes, @{$$this->{array}} ) ;
  69         158  
1262             } else {
1263              
1264 3         7 push( @hashes, $$this->{point} ) ;
1265              
1266 3 50       15 if( ref $$this->{point} eq 'HASH' ) {
1267 3         7 foreach my $k ( sort keys %{$$this->{point}} ) {
  3         23  
1268 15 100       62 push( @hashes, [$k,$$this->{point}{$k}]) if( ref($$this->{point}{$k}) eq 'HASH' ) ;
1269             }
1270             }
1271             }
1272            
1273 72         160 my $i = -1 ;
1274 72         210 my (@hash , @i) ;
1275 72         115 my $notwant = !wantarray ;
1276            
1277 72         132 foreach my $hash_i ( @hashes ) {
1278              
1279 219         305 foreach my $search_i ( @search ) {
1280              
1281 222         228 my ($name , $type , $value) = @{$search_i} ;
  222         2046  
1282 222         443 $type =~ s/\s//gs ;
1283            
1284 222         221 $i++ ;
1285 222         224 my $hash ;
1286 222 100       442 if (ref $hash_i eq 'ARRAY') { $hash = @$hash_i[1] ;}
  12         24  
1287 210         246 else { $hash = $hash_i ;}
1288            
1289 222         202 my $data ;
1290 222 50       470 if ($name =~ /^content$/i) { $name = 'CONTENT' ;}
  0         0  
1291 222 50       564 $data = ref($hash) eq 'HASH' ? $$hash{$name} : $hash ;
1292 222 100       452 $data = $$data{CONTENT} if ref($data) eq 'HASH' ;
1293            
1294 222         2253 _unset_sig_warn() ;
1295 222 100 100     4426 if ($type eq 'eq' && $data eq $value) { push(@hash,$hash_i) ; push(@i,$i) ; last ;}
  63 50 33     89  
  63 50 33     83  
  63 50 33     116  
    50 33        
    100 100        
    50 33        
    50 33        
    100 100        
    50 33        
    50 33        
    50 33        
1296 0         0 elsif ($type eq 'ne' && $data ne $value) { push(@hash,$hash_i) ; push(@i,$i) ; last ;}
  0         0  
  0         0  
1297 0         0 elsif ($type eq '==' && $data == $value) { push(@hash,$hash_i) ; push(@i,$i) ; last ;}
  0         0  
  0         0  
1298 0         0 elsif ($type eq '!=' && $data != $value) { push(@hash,$hash_i) ; push(@i,$i) ; last ;}
  0         0  
  0         0  
1299 0         0 elsif ($type eq '<=' && $data <= $value) { push(@hash,$hash_i) ; push(@i,$i) ; last ;}
  0         0  
  0         0  
1300 21         37 elsif ($type eq '>=' && $data >= $value) { push(@hash,$hash_i) ; push(@i,$i) ; last ;}
  21         37  
  21         45  
1301 0         0 elsif ($type eq '<' && $data < $value) { push(@hash,$hash_i) ; push(@i,$i) ; last ;}
  0         0  
  0         0  
1302 0         0 elsif ($type eq '>' && $data > $value) { push(@hash,$hash_i) ; push(@i,$i) ; last ;}
  0         0  
  0         0  
1303 6         11 elsif ($type eq '=~' && $data =~ /$value/s) { push(@hash,$hash_i) ; push(@i,$i) ; last ;}
  6         7  
  6         15  
1304 0         0 elsif ($type eq '=~i' && $data =~ /$value/is) { push(@hash,$hash_i) ; push(@i,$i) ; last ;}
  0         0  
  0         0  
1305 0         0 elsif ($type eq '!~' && $data !~ /$value/s) { push(@hash,$hash_i) ; push(@i,$i) ; last ;}
  0         0  
  0         0  
1306 0         0 elsif ($type eq '!~i' && $data !~ /$value/is) { push(@hash,$hash_i) ; push(@i,$i) ; last ;}
  0         0  
  0         0  
1307 132         318 _reset_sig_warn() ;
1308             }
1309              
1310 219 100 100     971 if( $notwant && @hash ) {
1311 63         80 last ;
1312             }
1313             }
1314            
1315 72         199 my $back = $$this->{back} ;
1316            
1317             #print "FIND>> @{$$this->{keyprev}} >> $i\n" ;
1318            
1319 72 50       150 if( @hash ) {
1320 72 100       137 if( $notwant ) {
1321 63         90 my ($k,$hash) = (undef) ;
1322 63 50       136 if (ref $hash[0] eq 'ARRAY') { ($k,$hash) = @{$hash[0]} ;}
  0         0  
  0         0  
1323 63         84 else { $hash = $hash[0] ;}
1324 63         154 return &XML::Smart::clone($this,$hash,$back,undef, $k,$i[0]) ;
1325             }
1326             else {
1327 9         19 my $c = -1 ;
1328 9         19 foreach my $hash_i ( @hash ) {
1329 27         28 $c++ ;
1330 27         851 my ($k,$hash) = (undef) ;
1331 27 100       62 if (ref $hash_i eq 'ARRAY') { ($k,$hash) = @{$hash_i} ;}
  6         7  
  6         16  
1332 21         26 else { $hash = $hash_i ;}
1333 27         65 $hash_i = &XML::Smart::clone($this,$hash,$back,undef, $k,$i[$c]) ;
1334             }
1335 9         53 return( @hash ) ;
1336             }
1337             }
1338            
1339 0 0       0 if (wantarray) { return() ;}
  0         0  
1340 0         0 return &XML::Smart::clone($this,'') ;
1341             }
1342              
1343             ###########
1344             # CONTENT #
1345             ###########
1346             sub content {
1347              
1348 250     250 1 17327 my $this = shift ;
1349 250 100       656 my $set_i = $#_ > 0 ? shift : undef ;
1350            
1351 250 100       543 if ( $this->null ) {
1352 3         25 &XML::Smart::Tie::_generate_nulltree( $$this ) ;
1353             }
1354            
1355             ##use Data::Dumper; print Dumper($$this) ;
1356            
1357 250         291 my $content_to_return ;
1358 250 100 66     1125 if ( defined $$this->{content} and ( !defined( $content_to_return ) ) ) {
1359 153 50       322 if (@_) { ${$$this->{content}} = $_[0] ;}
  0         0  
  0         0  
1360 153         184 $content_to_return = ${$$this->{content}} ;
  153         374  
1361             }
1362              
1363 250         334 my $key = 'CONTENT' ;
1364 250         410 my $i = $$this->{i} ;
1365            
1366 250 50 33     737 if( ( ref($$this->{point}) eq 'ARRAY' ) and ( !defined( $content_to_return ) ) ) {
1367 0         0 $content_to_return = $this->[0]->content($set_i,@_) ;
1368             }
1369              
1370 250 50 33     713 if( ( ref($$this->{point}) ne 'HASH' ) and ( !defined( $content_to_return ) ) ) {
1371 0         0 $content_to_return = '' ;
1372             }
1373            
1374 250 100 66     803 if( ( !exists $$this->{point}{$key} ) and ( !defined( $content_to_return ) ) ) {
1375 3 50       9 if( @_ ) {
1376 3         10 $content_to_return = $$this->{point}{$key} = $_[0] ;
1377             } else {
1378 0         0 $content_to_return = '' ;
1379             }
1380             }
1381            
1382 250 100       478 if( defined( $content_to_return ) ) {
1383 156         1068 return $content_to_return ;
1384             }
1385              
1386            
1387 94 50 33     665 if( ( ref($$this->{point}{$key}) eq 'ARRAY' ) and ( !defined( $content_to_return ) ) ) {
    50 33        
1388              
1389 0 0       0 if($i eq '') {
1390 0         0 $i = 0 ;
1391             }
1392              
1393 0 0       0 if(@_) {
1394 0         0 $$this->{point}{$key}[$i] = $_[0] ;
1395             }
1396              
1397 0         0 $content_to_return = $$this->{point}{$key}[$i] ;
1398              
1399             } elsif( ( exists $$this->{point}{$key} ) and ( !defined( $content_to_return ) ) ) {
1400            
1401 94 100       187 if ( @_ ) {
1402 9 100       29 if ( my $tie = tied($$this->{point}{$key}) ) {
1403 3         19 $tie->STORE($set_i , $_[0]) ;
1404             } else {
1405 6         19 $$this->{point}{$key} = $_[0] ;
1406             }
1407             }
1408              
1409 94 100 66     251 if( wantarray && ( my $tie = tied($$this->{point}{$key} ) ) ) {
1410 3         12 my @tmp = $tie->FETCH(1) ;
1411 3         8 $content_to_return = \@tmp ;
1412             } else {
1413 91         228 $content_to_return = $$this->{point}{$key} ;
1414             }
1415              
1416             }
1417              
1418 94 50       186 unless( defined( $content_to_return ) ) {
1419 0         0 $content_to_return = '' ;
1420             }
1421            
1422 94 100       147 if( wantarray ) {
1423 3         3 return @{ $content_to_return } ;
  3         14  
1424             } else {
1425 91         678 return $content_to_return ;
1426             }
1427              
1428             }
1429              
1430             ########
1431             # SAVE #
1432             ########
1433              
1434             sub save {
1435              
1436 0     0 1 0 my $this = shift ;
1437 0         0 my $file = shift ;
1438            
1439 0 0 0     0 if(-d $file || (-e $file && !-w $file)) {
      0        
1440 0         0 return ;
1441             }
1442            
1443 0         0 my( $data, $unicode ) = $this->data(@_) ;
1444            
1445 0         0 my $fh ;
1446 0         0 open($fh,">$file") ;
1447 0 0       0 binmode($fh) if $unicode ;
1448 0         0 print $fh $data ;
1449 0         0 close($fh) ;
1450            
1451 0         0 return( 1 ) ;
1452            
1453             }
1454              
1455             ################
1456             # DATA_POINTER #
1457             ################
1458              
1459             sub data_pointer {
1460              
1461 0     0 1 0 my $this = shift ;
1462 0 0       0 if( $this->null ) {
1463 0         0 return ;
1464             }
1465            
1466 0         0 my( $point, $key ) ;
1467            
1468 0 0       0 if ( exists $$this->{content} ) {
1469 0         0 my $back = $this->back ;
1470 0         0 my $root = $back->key ;
1471 0         0 my $k = $this->key ;
1472 0         0 $point = $back->pointer ;
1473 0         0 $point = $$point{ $this->key } ;
1474 0         0 $point = {$root => {$k => $point} } ;
1475             } else {
1476 0         0 $point = $$this->{point} ;
1477 0         0 $key = $this->key ;
1478             }
1479            
1480 0         0 $this->data( tree => $point , root => $key , @_) ;
1481            
1482             }
1483              
1484             ###########
1485             # DESTROY #
1486             ###########
1487              
1488             sub DESTROY {
1489              
1490 1873     1873   254761 my $this = shift ;
1491            
1492 1873 50       5622 if( $$this->{ DEV_DEBUG } ) {
1493 0         0 require Devel::Cycle ;
1494 0         0 my $circ_ref = 0 ;
1495             my $tmp = Devel::Cycle::find_cycle(
1496             $this,
1497             sub {
1498 0     0   0 my $path = shift;
1499 0         0 foreach (@$path) {
1500 0         0 my ($type,$index,$ref,$value) = @$_;
1501 0         0 $circ_ref = 1 ;
1502            
1503             }
1504            
1505 0         0 });
1506            
1507 0 0       0 if( $circ_ref ) {
1508 0         0 $this->ANNIHILATE() ;
1509             my $tmp = Devel::Cycle::find_cycle(
1510             $this,
1511             sub {
1512 0     0   0 print STDERR "Circular reference found while destroying object - AFTER ANNIHILATE\n" ;
1513 0         0 });
1514             }
1515             }
1516            
1517 1873 100 66     4957 $$this->clean if( $this && $$this ) ; # In case object was messed with ( bug 62091 )
1518            
1519            
1520             }
1521              
1522             sub ANNIHILATE {
1523            
1524 0     0 1   my $this = shift ;
1525 0           my $base = shift ;
1526            
1527 0 0         if( ref $$this->{ point } eq 'HASH' ) {
1528 0           my %clean ;
1529 0           $$this->{ point } = \%clean ;
1530             } else {
1531 0           $this->{ point }->ANNIHILATE( ) ;
1532             }
1533            
1534 0 0         if( ref $$this->{ tree } eq 'HASH' ) {
1535 0           my %clean ;
1536 0           $$this->{ tree } = \%clean ;
1537             } else {
1538 0           $this->{ tree }->ANNIHILATE( ) ;
1539             }
1540            
1541            
1542 0 0         if( ref $$this->{ back } eq 'HASH' ) {
1543 0           my %clean ;
1544 0           $$this->{ back } = \%clean ;
1545             } else {
1546 0           $this->{ back }->ANNIHILATE( ) ;
1547             }
1548            
1549 0 0         if( $$this->{ XPATH } ) { # and ( ref $$this->{ XPATH } eq 'XML::XPath' ) ) {
1550 0           my $xpath = $$this->{ XPATH } ;
1551 0           $$xpath->cleanup() ;
1552 0           my $context = $$xpath->{ _context } ;
1553 0           my $context_ref = ref $context ;
1554 0 0         if( $context_ref =~ /XML\:\:XPath\:\:Node\:\:/ ) {
1555 0           _xml_xpath_clean( $context ) ;
1556             }
1557             }
1558            
1559 0           $$this->DESTROY();
1560              
1561 0           return 1 ;
1562            
1563             }
1564              
1565              
1566             sub _xml_xpath_clean {
1567            
1568 0     0     my $path = shift ;
1569            
1570 0           $path->dispose() ;
1571             # Data::Structure::Util::unbless( $path ) ;
1572            
1573 0           return ;
1574            
1575             }
1576              
1577             ###################
1578             # STORABLE_FREEZE #
1579             ###################
1580              
1581             sub STORABLE_freeze {
1582 0     0 0   my $this = shift ;
1583 0           return($this , [$$this->{tree} , $$this->{pointer}]) ;
1584             }
1585              
1586             #################
1587             # STORABLE_THAW #
1588             #################
1589              
1590             sub STORABLE_thaw {
1591 0     0 0   my $this = shift ;
1592 0           $$this->{tree} = $_[1]->[0] ;
1593 0           $$this->{pointer} = $_[1]->[1] ;
1594 0           return ;
1595             }
1596              
1597             #######
1598             # END #
1599             #######
1600              
1601             1;
1602              
1603             __END__