File Coverage

blib/lib/Data/Dump/XML/Parser.pm
Criterion Covered Total %
statement 6 6 100.0
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 8 8 100.0


line stmt bran cond sub pod time code
1             package Data::Dump::XML::Parser;
2             #
3             # Once upon a time this file was a part of ACIS software,
4             # http://acis.openlib.org/
5             #
6             # Description:
7             #
8             # Parse an Data::Dump::XML-dumped XML string and recreate the
9             # data structure.
10             #
11             # This module is tightly related to Data::Dump::XML, which is
12             # based on Data::DumpXML, and it is accordingly based on
13             # Data::DumpXML::Parser.
14             #
15             # Copyright 2004-2009 Ivan Baktsheev
16             # Copyright 2003 Ivan Baktsheev, Ivan Kurmanov
17             # Copyright 1998-2003 Gisle Aas.
18             # Copyright 1996-1998 Gurusamy Sarathy.
19             #
20             # XXX use of GNU GPL here is questionable.
21             #
22             # This program is free software; you can redistribute it and/or modify
23             # it under the terms of the GNU General Public License, version 2, as
24             # published by the Free Software Foundation.
25             #
26             # This program is distributed in the hope that it will be useful,
27             # but WITHOUT ANY WARRANTY; without even the implied warranty of
28             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29             # GNU General Public License for more details.
30             #
31             # You should have received a copy of the GNU General Public License
32             # along with this program; if not, write to the Free Software
33             # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34             #
35             # ---
36             # $Id: Parser.pm,v 1.16 2009/06/07 20:22:56 apla Exp $
37             # ---
38              
39 5     5   15057 use Class::Easy;
  5         12  
  5         44  
40              
41 5     5   738 use base qw(XML::LibXML::SAX);
  5         9  
  5         4645  
42              
43             use Data::Dump::XML;
44              
45             our $VERSION = 1.19;
46              
47             # require XSLoader;
48             # XSLoader::load ('Data::Dump::XML::Parser', $VERSION);
49              
50             #*characters = \&Data::Dump::XML::characters;
51              
52             sub new {
53             my($class, %arg) = @_;
54            
55             Data::Dump::XML->new
56             unless defined $Data::Dump::XML::INSTANCE;
57            
58             $arg{defaults} = {%$Data::Dump::XML::defaults};
59            
60             return bless \%arg, $class;
61             }
62              
63             sub start_document {
64             my $p = shift;
65            
66             # real restored data
67             $p->{data} = undef;
68            
69             # data stack. used for control child/parent axe
70             $p->{stack} = [];
71            
72             push @{$p->{stack}}, \$p->{data};
73            
74             # current depth
75             $p->{depth} = 0;
76             }
77              
78             sub start_element {
79             my ($p, $element) = @_;
80            
81             my $d = $p->{defaults};
82            
83             my %attr = map {$_->{LocalName} => $_->{Value}}
84             values %{$element->{Attributes}};
85             my $tag = $element->{LocalName};
86            
87             my $depth = \$p->{depth};
88             $$depth++;
89            
90             $p->{max_depth} = $$depth;
91            
92             if ($$depth == 1) {
93            
94             $d->{'root_name'} = $tag;
95            
96             foreach (qw(ref_element hash_element array_element empty_array
97             empty_hash undef key_as_hash_element at_key_as_attribute hash_element_attribute_name)
98             ) {
99             $d->{$_} = delete $attr{"_$_"}
100             if exists $attr{"_$_"};
101             }
102            
103             }
104            
105             my $key_as_hash_element = $d->{'key_as_hash_element'};
106             my $root_name = $d->{'root_name'};
107             my $ref_element = $d->{'ref_element'};
108             my $array_element = $d->{'array_element'};
109             my $hash_element = $d->{'hash_element'};
110             my $empty_array = $d->{'empty_array'};
111             my $undef = $d->{'undef'};
112             my $empty_hash = $d->{'empty_hash'};
113            
114             my $blesser;
115             $blesser = $p->{Blesser}
116             if (exists $p->{Blesser} and ref($blesser) eq "CODE");
117            
118             my $parent_attr = $p->{attr}->[-1];
119             my $parent_class = delete $parent_attr->{_class};
120             my $parent_id = delete $parent_attr->{_id};
121            
122             my $ref = $p->{'stack'}->[-1];
123            
124             #my $defined_parent = 0;
125             #$defined_parent = 1
126             # if ref $p->{'stack'}->[-1] eq 'SCALAR'
127             # and not defined ${$p->{'stack'}->[-1]};
128            
129             push (@{$p->{'attr'}}, \%attr);
130            
131             if ($$depth == 1) {# and not defined $ref) {
132             # root element
133             } elsif ($tag eq $array_element) {
134             #$$ref = []
135             # if $defined_parent;
136            
137             ### check the data type
138             die "'$tag' elements only appear in list elements"
139             if defined $$ref and Data::Dump::XML::reftype ($$ref) ne 'ARRAY';
140            
141             push @{$$ref}, undef;
142             push @{$p->{'stack'}}, \($$ref->[-1]);
143            
144             $blesser ? &$blesser ($$ref, $parent_class) : bless ($$ref, $parent_class)
145             if defined $parent_class;
146              
147            
148             } elsif ($tag eq $ref_element) {
149             my $value = undef;
150             $$ref = \$value;
151            
152             $$ref = ${$p->{'id'}->[$attr{'to'}]}
153             if (defined $attr{'to'});
154            
155             push @{$p->{'stack'}}, $$ref;
156            
157             } elsif ($tag eq $undef) {
158            
159             $$ref = undef;
160             push @{$p->{'stack'}}, undef;
161            
162             } elsif ($tag eq $empty_hash) {
163            
164             $$ref = {};
165             push @{$p->{'stack'}}, undef;
166            
167             } elsif ($tag eq $empty_array) {
168            
169             $$ref = [];
170             push @{$p->{'stack'}}, undef;
171            
172             } elsif ($key_as_hash_element or ($tag eq $hash_element and exists $attr{$d->{hash_element_attribute_name}})) {
173             #$$ref = {}
174             # if $defined_parent;
175            
176             my $key = $tag;
177             $key = delete $attr{$d->{hash_element_attribute_name}}
178             if exists $attr{$d->{hash_element_attribute_name}};
179            
180             die "hash element '$key' must appear in hash context"
181             if defined $$ref and Data::Dump::XML::reftype ($$ref) ne 'HASH';
182            
183             unless (defined $$ref) {
184             # copy all attributes except _*
185             foreach my $k (keys %$parent_attr) {
186             # next if substr ($k, 0, 1) eq '_';
187             $$ref->{"\@$k"} = $parent_attr->{$k};
188             }
189             }
190            
191             die "hash element '$key' already present"
192             if exists $$ref->{$key};
193             $$ref->{$key} = undef;
194            
195             push @{$p->{stack}}, \(${$ref}->{$key});
196            
197             $blesser ? &$blesser ($$ref, $parent_class) : bless ($$ref, $parent_class)
198             if defined $parent_class;
199             } else {
200             warn "found unknown element $tag";
201             }
202            
203             # mix of pcdata and elements not allowed, ignore chars
204             $p->{char} = '';
205            
206             $p->{id}->[$parent_id] = $ref
207             if ($parent_id);
208             }
209              
210             sub characters {
211             my ($p, $str) = @_;
212             $p->{'char'} .= $str->{'Data'}
213             if defined $str->{'Data'};
214             }
215              
216             sub end_element {
217             my ($p, $element) = @_;
218            
219             my $d = $p->{defaults};
220            
221             my $tag = $element->{'LocalName'};
222            
223             my $depth = \$p->{depth};
224             my $str = $p->{'char'};
225             my $ref = pop @{$p->{'stack'}};
226            
227             $p->{'char'} = '';
228            
229             my $attr = pop @{$p->{'attr'}};
230             my $attributed_keys = {map {$_ => $attr->{$_}} grep {!/^_/} keys %$attr};
231            
232             my $has_attrs = scalar keys %$attributed_keys;
233            
234             if( $$depth < $p->{max_depth}) {
235             #print ' 'x $$depth, "- this element had children\n";
236             } else {
237             # here processing for empty tags
238            
239             #my $key = $tag;
240             #$key = delete $attr{$d->{hash_element_attribute_name}}
241             # if exists $attr{$d->{hash_element_attribute_name}};
242              
243              
244             if (
245             # ($tag eq $d->{array_element} or $tag eq $d->{hash_element}) and
246             $has_attrs
247             ) {
248             $$ref->{'#text'} = $str
249             if defined $str and $str ne '';
250            
251             foreach my $k (keys %$attributed_keys) {
252             $$ref->{"\@$k"} = $attributed_keys->{$k};
253             }
254            
255             } elsif ($tag ne $d->{'undef'}) {
256             if ($tag eq $d->{ref_element} and $attr->{'to'}) {
257             # print "'", $p->{'attr'}->[0]->{'to'}, "'\n";
258             # my $place = $p->{'attr'}->[0]->{'to'};
259             #
260             # $$ref = ${$p->{'id'}->[$place]}
261             # if (defined $place);
262            
263             } else {
264             #print ' 'x $$depth, "element '$tag' holds a string value ('$str')\n";
265             $$ref = $str;
266             }
267             }
268              
269             my $class = $attr->{_class};
270            
271             my $blesser;
272             $blesser = $p->{Blesser}
273             if (exists $p->{Blesser} and ref ($blesser) eq "CODE");
274              
275             $blesser ? &$blesser ($$ref, $class) : bless ($$ref, $class)
276             if defined $class and ref $$ref;
277              
278             }
279            
280             $$depth--;
281             }
282              
283             sub end_document {
284             my $p = shift;
285             my $data = $p->{'data'};
286            
287             return $data;
288             }
289              
290             1;
291              
292             __END__