File Coverage

blib/lib/Treex/PML/Backend/PML.pm
Criterion Covered Total %
statement 99 128 77.3
branch 25 60 41.6
condition 12 47 25.5
subroutine 20 20 100.0
pod 0 5 0.0
total 156 260 60.0


line stmt bran cond sub pod time code
1             package Treex::PML::Backend::PML;
2              
3 8     8   54 use Treex::PML;
  8         18  
  8         1067  
4 8     8   52 use Treex::PML::IO qw(close_backend);
  8         16  
  8         445  
5 8     8   40 use strict;
  8         15  
  8         222  
6 8     8   31 use warnings;
  8         17  
  8         426  
7 8     8   4289 use File::ShareDir;
  8         261653  
  8         519  
8 8     8   76 use File::Spec;
  8         19  
  8         235  
9              
10 8     8   39 use vars qw($VERSION);
  8         17  
  8         529  
11             BEGIN {
12 8     8   203 $VERSION='2.28'; # version template
13             }
14              
15 8     8   44 use Treex::PML::Instance qw( :all :diagnostics $DEBUG );
  8         14  
  8         2090  
16              
17 8     8   57 use constant EMPTY => q{};
  8         18  
  8         588  
18              
19 8     8   74 use Carp;
  8         14  
  8         564  
20              
21 8     8   45 use vars qw($config $config_file $allow_no_trees $config_inc_file $TRANSFORM @EXPORT_OK);
  8         17  
  8         567  
22              
23 8     8   40 use Exporter qw(import);
  8         14  
  8         662  
24              
25             BEGIN {
26 8     8   24 $TRANSFORM=0;
27 8         27 @EXPORT_OK = qw(open_backend close_backend test read write);
28 8         16 $config = undef;
29 8         15 $config_file = 'pmlbackend_conf.xml';
30 8         29 $config_inc_file = 'pmlbackend_conf.inc';
31 8         14529 $allow_no_trees = 0;
32             }
33              
34             sub configure {
35 8     8 0 46 my @resource_path = Treex::PML::ResourcePaths();
36 8         16 my $ret = eval { _configure() };
  8         23  
37 8         21 my $err = $@;
38 8         48 Treex::PML::SetResourcePaths(@resource_path);
39 8 50       27 die $err if ($err);
40 8         18 $config = $ret;
41 8         24 return $ret;
42             }
43              
44             sub _configure {
45 8     8   14 my $cfg;
46 8         15 my $schema_dir = eval { File::ShareDir::module_dir('Treex::PML') };
  8         34  
47 8 50 33     3750 unless (defined($schema_dir) and length($schema_dir) and -f File::Spec->catfile($schema_dir,'pmlbackend_conf_schema.xml')) {
      33        
48 8         102 $schema_dir = Treex::PML::IO::CallerDir(File::Spec->catfile(qw(.. share)));
49             }
50 8 50 33     81 Treex::PML::AddResourcePath($schema_dir) if defined($schema_dir) and length($schema_dir);
51 8         51 my $file = Treex::PML::FindInResources($config_file,{strict=>1});
52 8 50 33     52 if ($file and -f $file) {
53 0         0 _debug("config file: $file");
54 0         0 $cfg = Treex::PML::Instance->load({filename => $file});
55             } else {
56 8         54 _debug("using empty pmlbackend_conf.xml file");
57 8         112 $cfg = Treex::PML::Instance->load({string=><<'_CONFIG_',filename => $file});
58            
59            
60            
61            
62            
63             _CONFIG_
64             }
65 8 50       350 if ($cfg) {
66 8         97 my @config_files = Treex::PML::FindInResources($config_inc_file,{all=>1});
67 8   33     80 my $T = $cfg->get_root->{transform_map} ||= Treex::PML::Factory->createSeq();
68 8         31 for my $file (reverse @config_files) {
69 0         0 _debug("config include file: $file");
70 0         0 eval {
71 0         0 my $c = Treex::PML::Instance->load({filename => $file});
72             # merge
73 0         0 my $t = $c->get_root->{transform_map};
74 0 0       0 if ($t) {
75 0         0 for my $transform (reverse $t->elements) {
76 0         0 my $copy = Treex::PML::CloneValue($transform);
77 0         0 $T->unshift_element_obj($copy);
78 0 0 0     0 if (ref($copy->value) and $copy->value->{id}) {
79 0         0 $cfg->hash_id($copy->value->{id}, $copy->value, 1);
80             }
81             }
82             }
83             };
84 0 0       0 warn $@ if $@;
85             }
86             }
87 8         33 return $cfg;
88             }
89              
90              
91             ###################
92              
93             sub open_backend {
94 32     32 0 123 my ($filename, $mode, $encoding)=@_;
95 32   50     143 my $fh = Treex::PML::IO::open_backend($filename,$mode) # discard encoding
96             || die "Cannot open $filename for ".($mode eq 'w' ? 'writing' : 'reading').": $!";
97 32         159 return $fh;
98             }
99              
100             sub read ($$) {
101 22     22 0 68 my ($input, $fsfile)=@_;
102 22 50       73 return unless ref($fsfile);
103              
104 22         136 my $ctxt = Treex::PML::Instance->load({fh => $input, filename => $fsfile->filename, config => $config });
105 22         1410 $ctxt->convert_to_fsfile( $fsfile );
106 22         140 my $status = $ctxt->get_status;
107 22 50 0     106 if ($status and
      33        
108             !($allow_no_trees or defined($ctxt->get_trees))) {
109 0         0 _die("No trees found in the Treex::PML::Instance!");
110             }
111 22         453 return $status
112             }
113              
114              
115             sub write {
116 10     10 0 33 my ($fh,$fsfile)=@_;
117 10         104 my $ctxt = Treex::PML::Instance->convert_from_fsfile( $fsfile );
118 10         93 $ctxt->save({ fh => $fh, config => $config });
119             }
120              
121              
122             sub test {
123 44     44 0 131 my ($f,$encoding)=@_;
124 44 100       119 if (ref($f)) {
125 22         79 local $_;
126 22 50 33     101 if ($TRANSFORM and $config) {
127 0   0     0 1 while ($_=$f->getline() and !/\S/);
128             # see <, assume XML
129 0 0 0     0 return 1 if (defined and /^\s*
130             } else {
131             # only accept PML instances
132             # xmlns:...="..pml-namespace.." must occur in the first tag (on one line)
133              
134             # FIXME: the following code will fail for UTF-16 and UTF-32;
135             # proper fix would be to use XML::LibXML::Reader to read the
136             # first tag (performance impact on processing many files past
137             # PML backend to be measured). Another way to fix for UTF-16 is
138             # to check for UTF-16 BOM (both BE and LE) and decode
139             # accordingly if present; UTF-32 is rarely used and probably not
140             # worth fixing.
141 22         49 my ($in_first_tag,$in_pi,$in_comment, $past_BOM);
142 22         4366 while ($_=$f->getline()) {
143 49 100       212 unless ($past_BOM) {
144             # ignore UTF-8 BOM
145 22         74 s{^\x{ef}\x{bb}\x{bf}}{};
146 22         45 $past_BOM = 1;
147             }
148 49 100       202 next if !/\S/; # whitespace
149 44 50       205 if ($in_first_tag) {
    50          
    50          
150 0 0       0 last if />/;
151 0 0       0 return 1 if m{\bxmlns(?::[[:alnum:]]+)?=([\'\"])http://ufal.mff.cuni.cz/pdt/pml/\1};
152 0         0 next;
153             } elsif ($in_pi) {
154 0 0       0 next unless s/^.*?\?>//;
155 0         0 $in_pi=0;
156             } elsif ($in_comment) {
157 0 0       0 next unless s/^.*?\-->//;
158 0         0 $in_comment=0;
159             }
160 44         292 s/^(?:\s*<\?.*?\?>|\s*)*\s*//;
161 44 50       432 if (/<\?/) {
    50          
    100          
    50          
162 0         0 $in_pi=1;
163             } elsif (/