File Coverage

blib/lib/FileMetadata/Store/XML.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package FileMetadata::Store::XML;
2            
3             our $VERSION = '0.1';
4            
5 1     1   2275 use XML::Simple;
  0            
  0            
6            
7             =head1 NAME
8            
9             FileMetadata::Store::XML
10            
11             =cut
12            
13             use strict;
14            
15             =head1 DESCRIPTION
16            
17             This modules implements a store for the FileMetadata framework using a
18             XML file for storage. This module does not implement any methods for
19             accessing the information from the store.
20            
21             It is important to note that information is written to the XML file
22             only when the finish() method is called.
23            
24             =head1 METHODS
25            
26             =head2 new
27            
28             See L
29            
30             The new method creates and returns a reference to a new object.
31            
32             The format for the config hash is as follows
33            
34             {
35            
36             file => '/tmp/f00jkdw.xml',
37            
38             root_element => 'meta-info',
39            
40             item_element => 'item',
41            
42             store => [{name => 'id',
43            
44             property => 'ID',
45            
46             type => 'attribute'},
47            
48             {name => 'timestamp',
49            
50             property => 'TIMESTAMP',
51            
52             type => 'element'},
53            
54             {name => 'author',
55            
56             property => 'FileMetadata::Miner::HTML::author',
57            
58             default => 'Jules Verne'}
59            
60             ]
61            
62             }
63            
64             'file' is the path to which the information must be written. If the file
65             already exists, it is assumed to have been written with the same configuration.
66             The contents of the file are not checked for consistency with the given
67             configuration.
68            
69             'root_element' refers to the root element of the XML file. 'item_element' is
70             used as to enclose meta information for each item. These items are optional
71             and both would default to 'meta-info'. 'name' refers to the element or
72             attribute name with which the corresponding 'property' will be stored. 'type'
73             identifies whether the item should be written as a element or an attribute.
74             It is possible to generate illegal XML by using a invalid value for 'name'.
75             The 'default' value is used if the 'property' is not found in the meta hash as
76             a key. 'type' and 'default' are optional. If 'type' is not specified, it
77             defaults to 'element'. If 'default' is not specified, the property is ignored
78             if not found.
79            
80             The 'store' array is optional. If it is not present, each key in the
81             meta hash is used as an element name with the '::' replaced by '_'. If the
82             'store' array is provided, it must contain information for the 'ID' and
83             'TIMESTAMP' properties.
84            
85             The resulting XML output from this store would look as below.
86            
87            
88            
89            
90            
91             1020200222
92            
93             Scott Lee
94            
95            
96            
97            
98            
99             1320290459
100            
101             Timothy Walker
102            
103            
104            
105            
106            
107             =cut
108            
109             sub new {
110            
111             my $self = {};
112             bless $self, shift;
113             my $config = shift;
114             die "Config hash was not supplied" unless defined $config;
115            
116             # Read the basic config information
117             $self->{'root_element'} = $config->{'root_element'} or 'meta-info';
118             $self->{'item_element'} = $config->{'item_element'} or 'meta-info';
119             $self->{'file'} = $config->{'file'} or die 'config/file is needed';
120            
121             # Figure out element names
122            
123             if (defined $config->{'store'}) {
124            
125             foreach (@{$config->{'store'}}) {
126             die "config/store/name is needed" unless defined $_->{'name'};
127             die "config/store/property is needed" unless defined $_->{'property'};
128            
129             if ($_->{'property'} eq 'ID') {
130             $self->{'id_element'} = $_->{'name'};
131             } elsif ($_->{'property'} eq "TIMESTAMP") {
132             $self->{'timestamp_element'} = $_->{'name'};
133             }
134            
135             }
136            
137             die "config/store/property='ID' needs to be defined"
138             unless defined $self->{'id_element'};
139            
140             die "config/store/property='TIMESTAMP' needs to be defined"
141             unless defined $self->{'timestamp_element'};
142            
143             $self->{'store'} = $config->{'store'};
144            
145             } else {
146             $self->{'id_element'} = 'ID';
147             $self->{'timestamp_element'} = 'TIMESTAMP';
148             }
149            
150             # Construct the XML hash from a pre-existing file
151            
152             $self->{'data'} = {}; # This hash acts as internal storage for data
153             if (-f $self->{'file'}) {
154            
155             my $temp = XMLin ($config->{'file'},
156             keyattr => {});
157             if (ref ($temp->{$self->{'item_element'}}) eq 'ARRAY') {
158             foreach (@{$temp->{$self->{'item_element'}}}) {
159             my $id = $_->{$self->{'id_element'}};
160             $self->{'data'}->{$id} = $_;
161             }
162             } else {
163             # Assume it is a hash
164             my $id = $temp->{$self->{'item_element'}}->{$self->{'id_element'}};
165             $self->{'data'}->{$id} = $temp->{$self->{'item_element'}};
166             }
167             }
168            
169             return $self;
170             }
171            
172             =head2 store
173            
174             See L
175            
176             The store inserts required information from the meta hash into an internal
177             hash.
178            
179             =cut
180            
181             sub store {
182            
183             my ($self, $meta) = @_;
184            
185             if (defined $self->{'store'}) {
186            
187             my $meta_store = {};
188            
189             foreach (@{$self->{'store'}}) {
190            
191             # See if the item is in the hash
192             my $value;
193            
194             if (defined $meta->{$_->{'property'}}) {
195             $value = $meta->{$_->{'property'}};
196             } else {
197             $value = $_->{'default'};
198             }
199            
200             if (defined $value) {
201             $meta_store->{$_->{'name'}} = $value;
202             }
203             }
204            
205             my $id = $meta_store->{$self->{'id_element'}};
206             $self->{'data'}->{$id} = $meta_store;
207            
208             } else {
209            
210             my $meta_store = {};
211            
212             foreach (keys (%{$meta})) {
213             s/::/\-/g;
214             $meta_store->{$_} = $meta->{$_};
215             }
216            
217             my $id = $meta_store->{$self->{'id_element'}};
218             $self->{'data'}->{$id} = $meta_store;
219             }
220             }
221            
222             =head2 remove
223            
224             See L
225            
226             =cut
227            
228             sub remove {
229            
230             my ($self, $id) = @_;
231             delete $self->{'data'}->{$id};
232            
233             }
234            
235             =head2 clear
236            
237             See L
238            
239             =cut
240            
241             sub clear {
242            
243             my $self = shift;
244             $self->{'data'} = {};
245            
246             }
247            
248             =head2 has
249            
250             See L
251            
252             =cut
253            
254             sub has {
255            
256             my ($self, $id) = @_;
257            
258             if (defined $self->{'data'}->{$id}) {
259             my $temp = $self->{'timestamp_element'};
260             return $self->{'data'}->{$id}->{$temp};
261             } else {
262             return undef;
263             }
264            
265             }
266            
267             =head2 list
268            
269             See L
270            
271             =cut
272            
273             sub list {
274            
275             my $self = shift;
276             my @list = keys %{$self->{data}};
277             return \@list;
278            
279             }
280            
281             =head2 finish
282            
283             This method writes meta data held internally to the output file all at once.
284            
285             =cut
286            
287             sub finish {
288            
289             my $self = shift;
290            
291             my $temp = {};
292             my @temp_arr = values %{$self->{'data'}};
293             $temp->{$self->{'item_element'}} = \@temp_arr;
294            
295             XMLout ($temp,
296             rootname => $self->{'root_element'},
297             outputfile => $self->{'file'},
298             noattr => 1);
299            
300             }
301            
302             1;
303            
304             =head1 VERSION
305            
306             0.1 - This is the first release
307            
308             =head1 REQUIRES
309            
310             XML::Simple
311            
312             =head1 AUTHOR
313            
314             Midh Mulpuri midh@enjine.com
315            
316             =head1 LICENSE
317            
318             This software can be used under the terms of any Open Source Initiative
319             approved license. A list of these licenses are available at the OSI site -
320             http://www.opensource.org/licenses/
321            
322             =cut