File Coverage

blib/lib/XML/TMX/Reader.pm
Criterion Covered Total %
statement 12 14 85.7
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 17 19 89.4


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