File Coverage

blib/lib/xDT/Parser.pm
Criterion Covered Total %
statement 50 52 96.1
branch 9 18 50.0
condition 1 3 33.3
subroutine 12 12 100.0
pod 4 4 100.0
total 76 89 85.3


line stmt bran cond sub pod time code
1              
2             use v5.10;
3 2     2   114377 use Moose;
  2         17  
4 2     2   1298 use FileHandle;
  2         808860  
  2         18  
5 2     2   15383  
  2         18482  
  2         13  
6             use xDT::Record;
7 2     2   1698 use xDT::RecordType;
  2         8  
  2         86  
8 2     2   15 use xDT::Object;
  2         3  
  2         41  
9 2     2   1167  
  2         7  
  2         868  
10             =head1 NAME
11              
12             xDT::Parser - A Parser for xDT files.
13              
14             =head1 VERSION
15              
16             Version 1.06
17              
18             =cut
19              
20             our $VERSION = '1.07';
21              
22              
23             =head1 SYNOPSIS
24              
25             Can be used to open xdt files and strings, and to iterate over contained objects.
26              
27             use xDT::Parser;
28              
29             my $parser = xDT::Parser->new();
30             # or
31             my $parser = xDT::Parser->new(record_type_config => $config);
32             # or
33             my $parser = xDT::Parser->new(
34             record_type_config => xDT::Parser::build_config_from_xml($xml_file)
35             );
36             # or
37             my $parser = xDT::Parser->new(
38             record_type_config => JSON::Parser::read_json($json_file)
39             );
40              
41             # A record type configuration can be provided via xml file or arrayref and can be used to add
42             # metadata (like accessor string or labels) to each record type.
43              
44             $parser->open(file => $xdt_file); # read from file
45             # or
46             $parser->open(string => $xdt_string); # read from string
47              
48             while (my $object = $parser->next_object) { # iterate xdt objects
49             # ...
50             }
51              
52             $parser->close(); # close the file handle
53              
54             =head1 ATTRIBUTES
55              
56             =head2 fh
57              
58             FileHandle to the currently open file.
59              
60             =cut
61              
62             has 'fh' => (
63             is => 'rw',
64             isa => 'FileHandle',
65             documentation => q{The filehandle the parser will use to read xDT data.},
66             );
67              
68             =head2 record_type_config
69              
70             The C<RecordType> configurations.
71              
72             e.g.:
73              
74             [{
75             "id": "0201",
76             "length": "9",
77             "type": "num",
78             "accessor": "bsnr",
79             "labels": {
80             "en": "BSNR",
81             "de": "BSNR"
82             }
83             }]
84              
85             =cut
86              
87             has 'record_type_config' => (
88             is => 'rw',
89             isa => 'ArrayRef',
90             documentation => q{Contains configurations for record types.},
91             );
92              
93              
94             around BUILDARGS => sub {
95             my $orig = shift;
96             my $class = shift;
97              
98             if (@_ == 1) {
99             return $class->$orig(record_type_config => $_[0]);
100             } else {
101             my %params = @_;
102             return $class->$orig(\%params);
103             }
104             };
105              
106             =head1 SUBROUTINES/METHODS
107              
108             =head2 open
109              
110             $parser->open(file => 'example.gdt');
111             $parser->open(string => $xdt_string);
112              
113             Open a file or string with the parser.
114             If both file and string are given, the string will be ignored.
115             More information about the file format can be found at L<http://search.cpan.org/dist/xDT-RecordType/>.
116              
117             =cut
118              
119             my ($self, %args) = @_;
120              
121 3     3 1 16 my $file = $args{file};
122             my $string = $args{string};
123 3         9 my $fh;
124 3         11  
125 3         4 die 'Error: No file or string argument given to parse xDT.'
126             unless (defined $file or defined $string);
127 3 50 33     20  
128             if (defined $file) {
129             die "Error: Provided file '$file' does not exist or is not readable."
130 3 50       11 unless (-f $file);
131 0 0       0  
132             $fh = FileHandle->new($file, 'r')
133             or die "Error: Could not open file handle for '$file'.";
134 0 0       0 } else {
135             $fh = FileHandle->new(\$string, 'r')
136             or die 'Error: Could not open file handle for provided string.';
137 3 50       34 }
138              
139             $self->fh($fh);
140             }
141 3         1122  
142             =head2 close
143              
144             Closes the parsers filehandle
145              
146             =cut
147              
148             my $self = shift;
149              
150             close $self->fh;
151 1     1 1 3 }
152              
153 1         27 =head2 next_object
154              
155             Returns the next object from xDT.
156              
157             =cut
158              
159             my $self = shift;
160             my @records;
161              
162             while (my $record = $self->_next()) {
163 5     5 1 14 push @records, $record;
164 5         10 last if ($record->is_object_end);
165             }
166 5         29  
167 36         59 return undef unless (scalar @records);
168 36 50       95  
169             my $object = xDT::Object->new();
170             foreach my $record (@records) {
171 5 100       200 $object->add_record($record);
172             }
173 3         86  
174 3         12 return $object;
175 36         930 }
176              
177             =head2 build_config_from_xml
178 3         17  
179             Extracts metadata for a given record type id from a XML config file, if a file was given.
180             Otherwise id and accessor are set to the given id and all other attributes are undef.
181              
182             XML::Simple must be installed in order to use this method.
183              
184             Format of the XML config file:
185              
186             <RecordTypes>
187             <RecordType id="theId" length="theLength" type="theType" accessor="theAccessor">
188             <label lang="en">TheEnglishLabel</label>
189             <label lang="de">TheGermanLabel</label>
190             <!-- more labels -->
191             </RecordType>
192             <!-- more record types -->
193             </RecordTypes>
194              
195             =cut
196              
197             my $file = shift;
198              
199             return [] unless (length $file);
200              
201             use XML::Simple;
202 1     1 1 1947 return XML::Simple->new(
203             KeyAttr => { label => 'lang' },
204 1 50       6 GroupTags => { labels => 'label' },
205             ContentKey => '-content',
206 2     2   1755 )->XMLin($file)->{RecordType};
  2         16069  
  2         19  
207             }
208              
209             my $self = shift;
210             my $line;
211 1         10
212             do {
213             $line = $self->fh->getline() or return undef;
214             } while ($line =~ /^\s*$/);
215 41     41   76  
216 41         53 my $record = xDT::Record->new($line);
217             $record->set_record_type(xDT::RecordType::build_from_arrayref(
218 41         55 substr($line, 3, 4),
219 41 100       811 $self->record_type_config,
220             ));
221              
222 36         1738 return $record;
223 36         862 }
224              
225             =head1 AUTHOR
226              
227             Christoph Beger, C<< <christoph.beger at medizin.uni-leipzig.de> >>
228 36         113  
229             =cut
230              
231             __PACKAGE__->meta->make_immutable;
232              
233             1; # End of xDT::Parser