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 9     9   59 use Treex::PML;
  9         14  
  9         1116  
4 9     9   50 use Treex::PML::IO qw(close_backend);
  9         15  
  9         365  
5 9     9   51 use strict;
  9         26  
  9         191  
6 9     9   46 use warnings;
  9         34  
  9         458  
7 9     9   4289 use File::ShareDir;
  9         240762  
  9         530  
8 9     9   70 use File::Spec;
  9         16  
  9         200  
9              
10 9     9   35 use vars qw($VERSION);
  9         18  
  9         462  
11             BEGIN {
12 9     9   218 $VERSION='2.29'; # version template
13             }
14              
15 9     9   42 use Treex::PML::Instance qw( :all :diagnostics $DEBUG );
  9         16  
  9         1890  
16              
17 9     9   50 use constant EMPTY => q{};
  9         27  
  9         541  
18              
19 9     9   41 use Carp;
  9         16  
  9         467  
20              
21 9     9   56 use vars qw($config $config_file $allow_no_trees $config_inc_file $TRANSFORM @EXPORT_OK);
  9         65  
  9         625  
22              
23 9     9   44 use Exporter qw(import);
  9         18  
  9         595  
24              
25             BEGIN {
26 9     9   23 $TRANSFORM=0;
27 9         27 @EXPORT_OK = qw(open_backend close_backend test read write);
28 9         16 $config = undef;
29 9         16 $config_file = 'pmlbackend_conf.xml';
30 9         30 $config_inc_file = 'pmlbackend_conf.inc';
31 9         13653 $allow_no_trees = 0;
32             }
33              
34             sub configure {
35 9     9 0 45 my @resource_path = Treex::PML::ResourcePaths();
36 9         16 my $ret = eval { _configure() };
  9         42  
37 9         19 my $err = $@;
38 9         41 Treex::PML::SetResourcePaths(@resource_path);
39 9 50       25 die $err if ($err);
40 9         19 $config = $ret;
41 9         32 return $ret;
42             }
43              
44             sub _configure {
45 9     9   15 my $cfg;
46 9         14 my $schema_dir = eval { File::ShareDir::module_dir('Treex::PML') };
  9         35  
47 9 50 33     3362 unless (defined($schema_dir) and length($schema_dir) and -f File::Spec->catfile($schema_dir,'pmlbackend_conf_schema.xml')) {
      33        
48 9         101 $schema_dir = Treex::PML::IO::CallerDir(File::Spec->catfile(qw(.. share)));
49             }
50 9 50 33     93 Treex::PML::AddResourcePath($schema_dir) if defined($schema_dir) and length($schema_dir);
51 9         43 my $file = Treex::PML::FindInResources($config_file,{strict=>1});
52 9 50 33     42 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 9         49 _debug("using empty pmlbackend_conf.xml file");
57 9         106 $cfg = Treex::PML::Instance->load({string=><<'_CONFIG_',filename => $file});
58            
59            
60            
61            
62            
63             _CONFIG_
64             }
65 9 50       341 if ($cfg) {
66 9         69 my @config_files = Treex::PML::FindInResources($config_inc_file,{all=>1});
67 9   33     80 my $T = $cfg->get_root->{transform_map} ||= Treex::PML::Factory->createSeq();
68 9         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 9         60 return $cfg;
88             }
89              
90              
91             ###################
92              
93             sub open_backend {
94 32     32 0 79 my ($filename, $mode, $encoding)=@_;
95 32   50     118 my $fh = Treex::PML::IO::open_backend($filename,$mode) # discard encoding
96             || die "Cannot open $filename for ".($mode eq 'w' ? 'writing' : 'reading').": $!";
97 32         121 return $fh;
98             }
99              
100             sub read ($$) {
101 22     22 0 44 my ($input, $fsfile)=@_;
102 22 50       43 return unless ref($fsfile);
103              
104 22         86 my $ctxt = Treex::PML::Instance->load({fh => $input, filename => $fsfile->filename, config => $config });
105 22         973 $ctxt->convert_to_fsfile( $fsfile );
106 22         80 my $status = $ctxt->get_status;
107 22 50 0     62 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         311 return $status
112             }
113              
114              
115             sub write {
116 10     10 0 23 my ($fh,$fsfile)=@_;
117 10         85 my $ctxt = Treex::PML::Instance->convert_from_fsfile( $fsfile );
118 10         65 $ctxt->save({ fh => $fh, config => $config });
119             }
120              
121              
122             sub test {
123 44     44 0 80 my ($f,$encoding)=@_;
124 44 100       77 if (ref($f)) {
125 22         33 local $_;
126 22 50 33     82 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         1907 while ($_=$f->getline()) {
143 49 100       102 unless ($past_BOM) {
144             # ignore UTF-8 BOM
145 22         62 s{^\x{ef}\x{bb}\x{bf}}{};
146 22         30 $past_BOM = 1;
147             }
148 49 100       148 next if !/\S/; # whitespace
149 44 50       121 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         224 s/^(?:\s*<\?.*?\?>|\s*)*\s*//;
161 44 50       313 if (/<\?/) {
    50          
    100          
    50          
162 0         0 $in_pi=1;
163             } elsif (/