File Coverage

blib/lib/SGML/PYX.pm
Criterion Covered Total %
statement 79 80 98.7
branch 23 24 95.8
condition 6 6 100.0
subroutine 12 12 100.0
pod 2 2 100.0
total 122 124 98.3


line stmt bran cond sub pod time code
1             package SGML::PYX;
2              
3 12     12   355264 use strict;
  12         102  
  12         355  
4 12     12   71 use warnings;
  12         18  
  12         335  
5              
6 12     12   1358 use Class::Utils qw(set_params);
  12         74476  
  12         446  
7 12     12   6322 use Encode qw(decode_utf8 encode_utf8);
  12         108295  
  12         797  
8 12     12   86 use Error::Pure qw(err);
  12         20  
  12         401  
9 12     12   5593 use Tag::Reader::Perl;
  12         23219  
  12         388  
10 12     12   4715 use PYX qw(comment end_element char instruction start_element);
  12         85867  
  12         238  
11 12     12   948 use PYX::Utils qw(decode entity_decode);
  12         22  
  12         16929  
12              
13             our $VERSION = 0.07;
14              
15             # Constructor.
16             sub new {
17 47     47 1 30762 my ($class, @params) = @_;
18              
19             # Create object.
20 47         98 my $self = bless {}, $class;
21              
22             # Output callback.
23             $self->{'output'} = sub {
24 51     51   1093 my (@data) = @_;
25              
26 51         90 print join "\n", map { encode_utf8($_) } @data;
  86         350  
27 51         2196 print "\n";
28              
29 51         223 return;
30 47         284 };
31              
32             # Process params.
33 47         164 set_params($self, @params);
34              
35             # Object.
36 47         394 $self->{'_tag_reader'} = Tag::Reader::Perl->new;
37              
38             # Object.
39 47         1083 return $self;
40             }
41              
42             # Parse file.
43             sub parsefile {
44 46     46 1 32596 my ($self, $sgml_file) = @_;
45              
46             # Set file.
47 46         161 $self->{'_tag_reader'}->set_file($sgml_file);
48              
49             # Process.
50 46         3281 while (my ($data, $tag_type, $line, $column)
51             = $self->{'_tag_reader'}->gettoken) {
52              
53             # Decode data to internal form.
54 48         34537 $data = decode_utf8($data);
55              
56             # Data.
57 48 100       1546 if ($tag_type eq '!data') {
    100          
    100          
    100          
    100          
    100          
    50          
58 3         16 $self->{'output'}->(char(decode(entity_decode($data))));
59              
60             # Comment.
61             } elsif ($tag_type eq '!--') {
62 2         30 $data =~ s/^$//ms;
64 2         10 $self->{'output'}->(comment($data));
65              
66             # End of element.
67             } elsif ($tag_type =~ m/^\//ms) {
68 3         9 my $element = $data;
69 3         16 $element =~ s/^<\///ms;
70 3         14 $element =~ s/>$//ms;
71 3         11 $self->{'output'}->(end_element($element));
72              
73             # Begin of element.
74             } elsif ($tag_type =~ m/^\w+/ms) {
75 32         144 $data =~ s/^
76 32         159 $data =~ s/>$//ms;
77 32         51 my $end = 0;
78 32 100       81 if ($data =~ s/\/$//ms) {
79 5         5 $end = 1;
80             }
81 32         161 (my $element, $data) = ($data =~ m/^([^\s]+)\s*(.*)$/ms);
82 32         81 my @attrs = $self->_parse_attributes($data);
83 31         88 $self->{'output'}->(start_element($element, @attrs));
84 31 100       146 if ($end) {
85 5         16 $self->{'output'}->(end_element($element));
86             }
87              
88             # Doctype.
89             } elsif ($tag_type eq '!doctype') {
90             # Nop.
91              
92             # CData.
93             } elsif ($tag_type eq '![cdata[') {
94 4         36 $data =~ s/^
95 4         35 $data =~ s/\]\]>$//ms;
96 4         19 $self->{'output'}->(char(decode(entity_decode($data))));
97              
98             # Instruction.
99             } elsif ($tag_type =~ m/^\?/ms) {
100 3         35 $data =~ s/^<\?//ms;
101 3         26 $data =~ s/\s*\?>$//ms;
102 3         17 my ($target, $code) = split m/\s+/ms, $data, 2;
103 3         14 $self->{'output'}->(instruction($target, $code));
104              
105             } else {
106 0         0 err "Unsupported tag type '$tag_type'.";
107             }
108             }
109              
110 45         1624 return;
111             }
112              
113             # Parse attributes.
114             sub _parse_attributes {
115 32     32   49 my ($self, $data) = @_;
116              
117 32         37 my $original_data = $data;
118 32         46 my @attrs;
119 32         62 while ($data) {
120              
121             # or
122 36 100 100     276 if ($data =~ m/^([_\w:][\.\-\w:]*)\s*=\s*"(.*?)"\s*(.*)$/ms
    100 100        
    100          
123              
124             # or
125             || $data =~ m/^([_\w:][\.\-\w:]*)\s*=\s*'(.*?)'\s*(.*)$/ms
126              
127             # or .
128             || $data =~ m/^([_\w:][\.\-\w:]*)\s*=\s*([^\s]+)\s*(.*)$/ms) {
129              
130 28         79 push @attrs, $1, $2;
131 28         62 $data = $3;
132              
133             #
134             } elsif ($data =~ m/^([_\w:][\.\-\w:]*)\s*=\s*$/ms) {
135 3         8 push @attrs, $1, '';
136 3         7 $data = '';
137              
138             #
139             } elsif ($data =~ m/^([_\w:][\.\-\w:]*)\s*(.*)$/ms) {
140 4         10 push @attrs, $1, $1;
141 4         9 $data = $2;
142             } else {
143 1         6 err 'Problem with attribute parsing.',
144             'data', $original_data;
145             }
146             }
147              
148 31         80 return (@attrs);
149             }
150              
151             1;
152              
153             __END__