File Coverage

blib/lib/XML/TMX/Reader.pm
Criterion Covered Total %
statement 159 208 76.4
branch 60 104 57.6
condition 26 43 60.4
subroutine 25 32 78.1
pod 6 6 100.0
total 276 393 70.2


line stmt bran cond sub pod time code
1             package XML::TMX::Reader;
2             $XML::TMX::Reader::VERSION = '0.39';
3             # ABSTRACT: Perl extension for reading TMX files
4              
5 4     4   199422 use 5.010;
  4         34  
6 4     4   19 use warnings;
  4         9  
  4         88  
7 4     4   16 use strict;
  4         7  
  4         78  
8 4     4   17 use Exporter ();
  4         6  
  4         57  
9              
10 4     4   1948 use XML::DT;
  4         374742  
  4         864  
11 4     4   1809 use XML::TMX::Writer;
  4         13  
  4         181  
12 4     4   1798 use File::BOM qw( open_bom);
  4         40743  
  4         9358  
13              
14             our @ISA = 'Exporter';
15             our @EXPORT_OK = qw();
16              
17              
18             sub new {
19 6     6 1 172542 my ($class, $file) = @_;
20              
21 6 100       118 return undef unless -f $file;
22 5         50 my $self = bless {
23             encoding => _guess_encoding($file),
24             filename => $file,
25             ignore_markup => 1,
26             } => $class;
27 5         25 $self->_parse_header;
28 5         499 return $self;
29             }
30              
31             sub _guess_encoding {
32 5     5   16 my $file = shift;
33 5         14 my $encoding = 'UTF-8';
34 5         28 my $enc = open_bom (my $fh, $file, ":utf8"); # or die "can't open $file ($!)";
35 5 50       1049 $encoding= $enc if $enc;
36 5         125 my $line = <$fh>;
37 5 100       64 if ($line =~ /encoding=['"]([^'"]+)['"]/) {
38 3         17 $encoding = $1;
39             }
40             #print STDERR "Debug: defuse.ENC= $enc; enc=$encoding\n";
41 5         68 close $fh;
42 5         60 return $encoding;
43             }
44              
45 14     14   32 sub _enc2bin{ my $enc=shift;
46 14 50       119 if($enc =~ /utf.*8/i){
47 14         26 $enc = "utf8"
48             }
49 0         0 else {$enc = "encoding($enc)"}
50 14         68 return ":$enc";
51             }
52              
53             sub _parse_header {
54 5     5   14 my $self = shift;
55              
56 5         15 my $header = "";
57             {
58 5         11 my $fh;
  5         8  
59 5         22 local $/ = "";
60 5         42 open_bom($fh, $self->{filename},_enc2bin($self->{encoding})) ;# or die "$!";
61             #print STDERR "Debug2: defuse.ENC= $!- ; enc=$self->{encoding}\n";
62 5         689 $header = <$fh>;
63 5         79 close $fh;
64             }
65              
66 5         89 $header =~ s/^.*(
67 5         50 $header =~ s/(<\/header>).*$/$1/s;
68              
69 5         26 $header =~ s!().*$!$1!s;
70              
71             dtstring($header => (
72             'header' => sub {
73 5     5   289 $self->{header}{$_} = $v{$_} for (keys %v);
74             },
75             'prop' => sub {
76 10   50 10   3764 $v{type} ||= "_";
77 10         16 push @{$self->{header}{-prop}{$v{type}}}, $c;
  10         59  
78             },
79             'note' => sub {
80 10     10   847 push @{$self->{header}{-note}}, $c;
  10         55  
81             },
82 5         87 ));
83             }
84              
85              
86             sub ignore_markup {
87 0     0 1 0 my ($self, $opt) = @_;
88 0 0       0 $opt = 1 unless defined $opt;
89 0         0 $self->{ignore_markup} = $opt;
90             }
91              
92              
93             sub languages {
94 2     2 1 25 my $self = shift;
95 2         5 my %languages = ();
96             $self->for_tu({proc_tu => 100},
97             sub {
98 13     13   20 my $tu = shift;
99 13         33 for ( keys %$tu ) {
100 52 100       141 $languages{$_}++ unless m/^-/;
101             }
102 2         17 } );
103 2         19 return keys %languages;
104             }
105              
106              
107             sub _merge_notes {
108 12     12   137 my ($orig, $new) = @_;
109              
110 12   100     36 $orig //= [];
111 12 100       26 $orig = [$orig] unless ref $orig eq "ARRAY";
112 12 100       24 $new = [$new] unless ref $new eq "ARRAY";
113              
114 12         21 push @$orig => grep { my $x = $_; !grep { $x eq $_} @$orig } @$new;
  16         42  
  16         33  
  22         47  
115              
116 12         48 return $orig;
117             }
118              
119             sub _merge_props {
120 5     5   703 my ($orig, $new) = @_;
121 5 50 66     21 die "-prop should be hash" if $orig and ref $orig ne "HASH";
122 5 50 33     17 die "-prop should be hash" if $new and ref $new ne "HASH";
123              
124 5         13 for my $key (keys %$new) {
125 6         15 $orig->{$key} = _merge_notes($orig->{$key}, $new->{$key});
126             }
127 5         22 return $orig;
128             }
129              
130             sub _compute_header {
131 4     4   11 my ($current, $conf) = @_;
132 4         39 my %header = %$current;
133 4 50       15 if (exists($conf->{-note})) {
134 0         0 $header{-note} = _merge_notes($header{-note}, $conf->{-note});
135             }
136 4 50       10 if (exists($conf->{-prop})) {
137 0         0 $header{-prop} = _merge_props($header{-prop}, $conf->{-prop});
138             }
139 4         15 return \%header;
140             }
141              
142             sub for_tu {
143 9     9 1 5661 my $self = shift;
144 9         24 my $conf = { -header => 1 };
145 9         17 my $i = 0;
146              
147 9 100       39 ref($_[0]) eq "HASH" and $conf = {%$conf , %{shift(@_)}};
  6         19  
148              
149 9         17 my $code = shift;
150 9 50       23 die "invalid processor" unless ref($code) eq "CODE";
151              
152 9         25 local $/;
153              
154 9         12 my $outputingTMX = 0;
155 9         19 my $tmx;
156             my $data;
157 9         12 my $gen=0;
158             my %h = (
159             -type => { tu => 'SEQ', tuv => 'SEQ' },
160             tu => sub {
161 59     59   4553 my $tu;
162 59         98 for my $va (@$c) {
163 306 100       510 if ($va->[0] eq "-prop") {
    100          
164 87         89 push @{$tu->{$va->[0]}{$va->[1]}}, $va->[2]
  87         289  
165             } elsif ($va->[0] eq "-note") {
166 101         97 push @{$tu->{$va->[0]}}, $va->[1]
  101         179  
167             } else {
168 118         197 $tu->{$va->[0]} = $va->[1]
169             }
170             }
171 59         143 my ($ans, $v) = $code->($tu, \%v);
172              
173             # Check if the user wants to create a TMX and
174             # forgot to say us
175 59 50 100     510 if (!$outputingTMX && $ans && ref($ans) eq "HASH") {
      66        
176 0         0 $outputingTMX = 1;
177 0         0 $tmx = XML::TMX::Writer->new();
178 0 0       0 if ($conf->{-header}) {
179 0         0 my $header = _compute_header($self->{header}, $conf);
180 0         0 $tmx->start_tmx(encoding => $self->{encoding}, %$header);
181             }
182             }
183             # Add the translation unit
184 59 100 100     264 if ($ans && ref($ans) eq "HASH") {
185 20         29 $gen++;
186 20 50 33     32 %v = %$v if ($v && ref($v) eq "HASH");
187              
188 20         91 my %ans = (%v, %$ans);
189 20 50       51 $ans{"-n"}=$i if $conf->{n} ;
190 20         88 $tmx->add_tu(-verbatim => $conf->{-verbatim}, %ans);
191             }
192             },
193              
194             tuv => sub {
195 118     118   5022 my $tuv;
196 118         195 for my $v (@$c) {
197 154 100       376 if ($v->[0] eq "-prop") {
    100          
    50          
198 18         20 push @{$tuv->{$v->[0]}{$v->[1]}}, $v->[2]
  18         74  
199             } elsif ($v->[0] eq "-note") {
200 18         29 push @{$tuv->{$v->[0]}}, $v->[1]
  18         45  
201             } elsif ($v->[0] eq "-cdata") {
202 0         0 $tuv->{-iscdata} = 1;
203 0         0 $tuv->{-seg} = $v->[1];
204             } else {
205 118         221 $tuv->{-seg} = $v->[0];
206             }
207             }
208 118   50     532 [ $v{lang} || $v{'xml:lang'} || "_" => $tuv ]
209             },
210 105   50 105   31178 prop => sub { ["-prop", $v{type} || "_", $c] },
211 119     119   12130 note => sub { ["-note" , $c] },
212             seg => sub {
213 118 50   118   18144 return ($v{iscdata}) ? [ -cdata => $c ] : [ $c ]
214             },
215             -cdata => sub {
216 0     0   0 father->{'iscdata'} = 1; $c },
  0         0  
217 0 0   0   0 hi => sub { $self->{ignore_markup}?$c:toxml },
218 0 0   0   0 ph => sub { $self->{ignore_markup}?$c:toxml },
219 9         146 );
220              
221              
222 9         22 $/ = "\n";
223              
224 9         34 $h{-outputenc} = $h{-inputenc} = $self->{encoding};
225              
226 9         14 my $resto = "";
227             ## Go through the header...
228 9         12 my $fh;
229 9         27 open_bom($fh, $self->{filename},_enc2bin($self->{encoding})) ;# or die "$!";
230             #print STDERR "Debug2: defuse.ENC= $! ; enc=" ,_enc2bin($self->{encoding}),"\n";
231 9         1672 while (<$fh>) {
232 87 100       235 next if /^\s*$/;
233 75 100       185 last if /
234             }
235              
236 9 50       45 if (m!(.*?)()(.*)!s) {
237 9         25 $resto = $3;
238             }
239              
240              
241             # If we have an output filename, user wants to output a TMX
242 9 100       28 $conf->{-output} = $conf->{output} if defined($conf->{output});
243 9 100       23 if (defined($conf->{-output})) {
244 4         6 $outputingTMX = 1;
245 4         30 $tmx = XML::TMX::Writer->new();
246 4 50       11 if ($conf->{-header}) {
247 4         14 my $header = _compute_header($self->{header}, $conf);
248             $tmx->start_tmx(encoding => $self->{encoding},
249             -output => $conf->{-output},
250 4         24 %$header);
251             }
252             }
253              
254 9         25 $/ = "";
255 9 50       24 $conf->{-verbose}++ if $conf->{verbose};
256 9 50       19 print STDERR "." if $conf->{-verbose};
257 9         75 while (<$fh>) {
258 68 100 50     149 ($_ = $resto . $_ and $resto = "" ) if $resto;
259 68 100       211 last if /<\/body>/;
260 60         74 $i++;
261 60 50 33     125 print STDERR "\r$i" if $conf->{-verbose} && !($i % 10);
262 60 100 100     152 last if defined $conf->{proc_tu} && $i > $conf->{proc_tu} ;
263 59 50 66     126 last if defined $conf->{gen_tu} && $gen > $conf->{gen_tu};
264             # next if defined $conf->{patt} && !m/$conf->{patt}/ ;
265              
266 59 50       95 if (defined $conf->{patt}){ ## FIXME untested
267 0 0       0 if(ref($conf->{patt})){ ## EN=>/cat/ PT=>/gato/
268 0         0 my $ok = 1;
269 0         0 my $textli = "";
270 0         0 for my $li (keys %{$conf->{patt}}){
  0         0  
271 0         0 my $patli= $conf->{patt}{$li};
272 0 0       0 if (m!lang=["']$li['"](.*?)!is ) { $textli = $1 };
  0         0  
273 0   0     0 $ok &&= ($textli =~ /$patli/)
274             }
275 0 0       0 next unless $ok
276             }
277             else { ## /cat.*/
278 0 0       0 next if not m/$conf->{patt}/ ;
279             }
280             }
281             ####
282             # This can't be done. Not sure why it was being done.
283             # So, please, unless you know the implications for tagged crpora
284             # do not uncomment it.
285             # s/\>\s+/>/;
286 59         69 undef($data);
287 59 50       96 if ($conf->{'-raw'}) {
288 0         0 my $ans = $code->($_);
289 0 0       0 if ($conf->{-output}) {
290 0 0       0 $ans->{"-n"}=$i if $conf->{n} ;
291 0         0 $tmx->add_tu(-raw => $ans);
292             }
293             } else {
294 59         66 eval { dtstring($_, %h) } ; ## dont die in invalid XML
  59         204  
295 59 50       4230 warn $@ if $@;
296             }
297             }
298 9 50       37 print STDERR "\r$i\n" if $conf->{-verbose};
299 9         144 close $fh;
300              
301              
302 9 100 66     228 $tmx->end_tmx if $conf->{-header} && $outputingTMX;
303             }
304              
305              
306             sub to_html {
307 0     0 1   my $self = shift;
308 0           my %opt = @_;
309 0           my @ls=$self->languages;
310 0           my $html="". join("\n",map{""} @ls) ."\n";
$_
  0            
311             $self->for_tu(sub {
312 0     0     my ($langs, $opts) = @_;
313 0           my $ret = ""; # ""; " " \n" $ret\n\n";
314 0           for (@ls) {
315 0 0         if( defined $langs->{$_}){
316 0           $ret .= "\n\t$langs->{$_}{-seg}
317             }
318             else {
319 0           $ret .= "\n\t
320             }
321             }
322              
323             #if ($opt{icons}) {
324             # $ret .= "\"$_\"/"
325             # } else {
326             # $ret .= "$_"
327             # }
328             # $ret .= "$langs->{$_}{-seg}
329 0           $html.= "
330 0           return ""
331             }
332 0           );
333 0           return $html;
334             }
335              
336             sub for_tu2 {
337 0     0 1   warn "Please update your code to use 'for_tu'\n";
338 0           &for_tu;
339             }
340              
341              
342             1;
343              
344             __END__