| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#!/usr/bin/perl |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
351
|
use strict; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
26
|
|
|
4
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
31
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
# DO NOT RELY ON THIS AS A REAL XML PARSER! |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# It is not intended to be used actually as an XML parser, simply to stand as |
|
9
|
|
|
|
|
|
|
# an example of how you might use Parser::MGC to parse an XML-like syntax |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# There are a great many things it doesn't do correctly; it lacks at least the |
|
12
|
|
|
|
|
|
|
# following features: |
|
13
|
|
|
|
|
|
|
# Entities |
|
14
|
|
|
|
|
|
|
# Processing instructions |
|
15
|
|
|
|
|
|
|
# Comments |
|
16
|
|
|
|
|
|
|
# CDATA |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
package XmlParser; |
|
19
|
1
|
|
|
1
|
|
5
|
use base qw( Parser::MGC ); |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
458
|
|
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub parse |
|
22
|
|
|
|
|
|
|
{ |
|
23
|
5
|
|
|
5
|
|
5
|
my $self = shift; |
|
24
|
|
|
|
|
|
|
|
|
25
|
5
|
|
|
|
|
7
|
my $rootnode = $self->parse_node; |
|
26
|
5
|
50
|
|
|
|
9
|
$rootnode->kind eq "element" or die "Expected XML root node"; |
|
27
|
5
|
50
|
|
|
|
6
|
$rootnode->name eq "xml" or die "Expected XML root node"; |
|
28
|
|
|
|
|
|
|
|
|
29
|
5
|
|
|
|
|
9
|
return [ $rootnode->children ]; |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub parse_node |
|
33
|
|
|
|
|
|
|
{ |
|
34
|
28
|
|
|
28
|
|
25
|
my $self = shift; |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
# A "node" is either an XML element subtree or plaintext |
|
37
|
28
|
|
|
|
|
60
|
$self->any_of( 'parse_plaintext', 'parse_element' ); |
|
38
|
|
|
|
|
|
|
} |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub parse_plaintext |
|
41
|
|
|
|
|
|
|
{ |
|
42
|
28
|
|
|
28
|
|
28
|
my $self = shift; |
|
43
|
|
|
|
|
|
|
|
|
44
|
28
|
|
|
|
|
35
|
my $str = $self->substring_before( '<' ); |
|
45
|
28
|
100
|
|
|
|
64
|
$self->fail( "No plaintext" ) unless length $str; |
|
46
|
|
|
|
|
|
|
|
|
47
|
7
|
|
|
|
|
14
|
return XmlParser::Node::Plain->new( $str ); |
|
48
|
|
|
|
|
|
|
} |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub parse_element |
|
51
|
|
|
|
|
|
|
{ |
|
52
|
21
|
|
|
21
|
|
20
|
my $self = shift; |
|
53
|
|
|
|
|
|
|
|
|
54
|
21
|
|
|
|
|
25
|
my $tag = $self->parse_tag; |
|
55
|
|
|
|
|
|
|
|
|
56
|
11
|
|
|
|
|
24
|
$self->commit; |
|
57
|
|
|
|
|
|
|
|
|
58
|
11
|
100
|
|
|
|
16
|
return XmlParser::Node::Element->new( $tag->{name}, $tag->{attrs} ) if $tag->{selfclose}; |
|
59
|
|
|
|
|
|
|
|
|
60
|
10
|
|
|
|
|
17
|
my $childlist = $self->sequence_of( 'parse_node' ); |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
$self->parse_close_tag->{name} eq $tag->{name} |
|
63
|
10
|
50
|
|
|
|
28
|
or $self->fail( "Expected $tag->{name} to be closed" ); |
|
64
|
|
|
|
|
|
|
|
|
65
|
10
|
|
|
|
|
33
|
return XmlParser::Node::Element->new( $tag->{name}, $tag->{attrs}, @$childlist ); |
|
66
|
|
|
|
|
|
|
} |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
sub parse_tag |
|
69
|
|
|
|
|
|
|
{ |
|
70
|
21
|
|
|
21
|
|
18
|
my $self = shift; |
|
71
|
|
|
|
|
|
|
|
|
72
|
21
|
|
|
|
|
42
|
$self->expect( '<' ); |
|
73
|
21
|
|
|
|
|
36
|
my $tagname = $self->token_ident; |
|
74
|
|
|
|
|
|
|
|
|
75
|
11
|
|
|
|
|
21
|
my $attrs = $self->sequence_of( 'parse_tag_attr' ); |
|
76
|
|
|
|
|
|
|
|
|
77
|
11
|
|
|
|
|
16
|
my $selfclose = $self->maybe_expect( '/' ); |
|
78
|
11
|
|
|
|
|
25
|
$self->expect( '>' ); |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
return { |
|
81
|
|
|
|
|
|
|
name => $tagname, |
|
82
|
11
|
|
|
|
|
36
|
attrs => { map { ( $_->[0], $_->[1] ) } @$attrs }, |
|
|
2
|
|
|
|
|
8
|
|
|
83
|
|
|
|
|
|
|
selfclose => $selfclose, |
|
84
|
|
|
|
|
|
|
}; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub parse_close_tag |
|
88
|
|
|
|
|
|
|
{ |
|
89
|
10
|
|
|
10
|
|
10
|
my $self = shift; |
|
90
|
|
|
|
|
|
|
|
|
91
|
10
|
|
|
|
|
19
|
$self->expect( '' ); |
|
92
|
10
|
|
|
|
|
13
|
my $tagname = $self->token_ident; |
|
93
|
10
|
|
|
|
|
19
|
$self->expect( '>' ); |
|
94
|
|
|
|
|
|
|
|
|
95
|
10
|
|
|
|
|
25
|
return { name => $tagname }; |
|
96
|
|
|
|
|
|
|
} |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub parse_tag_attr |
|
99
|
|
|
|
|
|
|
{ |
|
100
|
13
|
|
|
13
|
|
14
|
my $self = shift; |
|
101
|
|
|
|
|
|
|
|
|
102
|
13
|
|
|
|
|
17
|
my $attrname = $self->token_ident; |
|
103
|
2
|
|
|
|
|
4
|
$self->expect( '=' ); |
|
104
|
2
|
|
|
|
|
3
|
return [ $attrname => $self->parse_tag_attr_value ]; |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
sub parse_tag_attr_value |
|
108
|
|
|
|
|
|
|
{ |
|
109
|
2
|
|
|
2
|
|
3
|
my $self = shift; |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# TODO: This sucks |
|
112
|
2
|
|
|
|
|
6
|
return $self->token_string; |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
|
|
116
|
1
|
|
|
1
|
|
498
|
use Data::Dumper; |
|
|
1
|
|
|
|
|
5664
|
|
|
|
1
|
|
|
|
|
110
|
|
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
if( !caller ) { |
|
119
|
|
|
|
|
|
|
my $parser = __PACKAGE__->new; |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
my $ret = $parser->from_file( \*STDIN ); |
|
122
|
|
|
|
|
|
|
print Dumper( $ret ); |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
package XmlParser::Node; |
|
127
|
18
|
|
|
18
|
|
18
|
sub new { my $class = shift; bless [ @_ ], $class } |
|
|
18
|
|
|
|
|
100
|
|
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
package XmlParser::Node::Plain; |
|
130
|
1
|
|
|
1
|
|
18
|
use base qw( XmlParser::Node ); |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
344
|
|
|
131
|
0
|
|
|
0
|
|
0
|
sub kind { "plain" } |
|
132
|
0
|
|
|
0
|
|
0
|
sub text { shift->[0] } |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
package XmlParser::Node::Element; |
|
135
|
1
|
|
|
1
|
|
6
|
use base qw( XmlParser::Node ); |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
238
|
|
|
136
|
5
|
|
|
5
|
|
10
|
sub kind { "element" } |
|
137
|
5
|
|
|
5
|
|
11
|
sub name { shift->[0] } |
|
138
|
0
|
|
|
0
|
|
0
|
sub attrs { shift->[1] } |
|
139
|
5
|
|
|
5
|
|
5
|
sub children { my $self = shift; @{$self}[2..$#$self] } |
|
|
5
|
|
|
|
|
7
|
|
|
|
5
|
|
|
|
|
18
|
|
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
1; |