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 6     6   44 use Treex::PML;
  6         17  
  6         726  
4 6     6   39 use Treex::PML::IO qw(close_backend);
  6         11  
  6         239  
5 6     6   31 use strict;
  6         14  
  6         108  
6 6     6   26 use warnings;
  6         11  
  6         205  
7 6     6   2725 use File::ShareDir;
  6         138804  
  6         275  
8 6     6   50 use File::Spec;
  6         13  
  6         139  
9              
10 6     6   32 use vars qw($VERSION);
  6         11  
  6         254  
11             BEGIN {
12 6     6   137 $VERSION='2.24'; # version template
13             }
14              
15 6     6   34 use Treex::PML::Instance qw( :all :diagnostics $DEBUG );
  6         11  
  6         1300  
16              
17 6     6   51 use constant EMPTY => q{};
  6         13  
  6         435  
18              
19 6     6   35 use Carp;
  6         13  
  6         326  
20              
21 6     6   32 use vars qw($config $config_file $allow_no_trees $config_inc_file $TRANSFORM @EXPORT_OK);
  6         15  
  6         381  
22              
23 6     6   32 use Exporter qw(import);
  6         13  
  6         311  
24              
25             BEGIN {
26 6     6   17 $TRANSFORM=0;
27 6         20 @EXPORT_OK = qw(open_backend close_backend test read write);
28 6         17 $config = undef;
29 6         15 $config_file = 'pmlbackend_conf.xml';
30 6         12 $config_inc_file = 'pmlbackend_conf.inc';
31 6         7691 $allow_no_trees = 0;
32             }
33              
34             sub configure {
35 6     6 0 38 my @resource_path = Treex::PML::ResourcePaths();
36 6         14 my $ret = eval { _configure() };
  6         20  
37 6         23 my $err = $@;
38 6         33 Treex::PML::SetResourcePaths(@resource_path);
39 6 50       16 die $err if ($err);
40 6         16 $config = $ret;
41 6         16 return $ret;
42             }
43              
44             sub _configure {
45 6     6   14 my $cfg;
46 6         12 my $schema_dir = eval { File::ShareDir::module_dir('Treex::PML') };
  6         28  
47 6 50 33     2807 unless (defined($schema_dir) and length($schema_dir) and -f File::Spec->catfile($schema_dir,'pmlbackend_conf_schema.xml')) {
      33        
48 6         76 $schema_dir = Treex::PML::IO::CallerDir(File::Spec->catfile(qw(.. share)));
49             }
50 6 50 33     92 Treex::PML::AddResourcePath($schema_dir) if defined($schema_dir) and length($schema_dir);
51 6         34 my $file = Treex::PML::FindInResources($config_file,{strict=>1});
52 6 50 33     39 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 6         40 _debug("using empty pmlbackend_conf.xml file");
57 6         65 $cfg = Treex::PML::Instance->load({string=><<'_CONFIG_',filename => $file});
58            
59            
60            
61            
62            
63             _CONFIG_
64             }
65 6 50       206 if ($cfg) {
66 6         47 my @config_files = Treex::PML::FindInResources($config_inc_file,{all=>1});
67 6   33     52 my $T = $cfg->get_root->{transform_map} ||= Treex::PML::Factory->createSeq();
68 6         26 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 6         22 return $cfg;
88             }
89              
90              
91             ###################
92              
93             sub open_backend {
94 32     32 0 101 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         133 return $fh;
98             }
99              
100             sub read ($$) {
101 22     22 0 63 my ($input, $fsfile)=@_;
102 22 50       85 return unless ref($fsfile);
103              
104 22         119 my $ctxt = Treex::PML::Instance->load({fh => $input, filename => $fsfile->filename, config => $config });
105 22         1078 $ctxt->convert_to_fsfile( $fsfile );
106 22         109 my $status = $ctxt->get_status;
107 22 50 0     81 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         317 return $status
112             }
113              
114              
115             sub write {
116 10     10 0 30 my ($fh,$fsfile)=@_;
117 10         95 my $ctxt = Treex::PML::Instance->convert_from_fsfile( $fsfile );
118 10         68 $ctxt->save({ fh => $fh, config => $config });
119             }
120              
121              
122             sub test {
123 44     44 0 102 my ($f,$encoding)=@_;
124 44 100       124 if (ref($f)) {
125 22         55 local $_;
126 22 50 33     95 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         59 my ($in_first_tag,$in_pi,$in_comment, $past_BOM);
142 22         875 while ($_=$f->getline()) {
143 49 100       3141 unless ($past_BOM) {
144             # ignore UTF-8 BOM
145 22         68 s{^\x{ef}\x{bb}\x{bf}}{};
146 22         56 $past_BOM = 1;
147             }
148 49 100       262 next if !/\S/; # whitespace
149 44 50       181 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         245 s/^(?:\s*<\?.*?\?>|\s*)*\s*//;
161 44 50       690 if (/<\?/) {
    50          
    100          
    50          
162 0         0 $in_pi=1;
163             } elsif (/