File Coverage

lib/MKDoc/XML/TreeBuilder.pm
Criterion Covered Total %
statement 58 63 92.0
branch 13 16 81.2
condition n/a
subroutine 7 7 100.0
pod 1 2 50.0
total 79 88 89.7


line stmt bran cond sub pod time code
1             # -------------------------------------------------------------------------------------
2             # MKDoc::XML::TreeBuilder
3             # -------------------------------------------------------------------------------------
4             # Author : Jean-Michel Hiver.
5             # Copyright : (c) MKDoc Holdings Ltd, 2003
6             #
7             # This module turns an XML string into a tree of elements and returns the top elements.
8             # This assumes that the XML string is well-formed. Well. More or less :)
9             #
10             # This module is distributed under the same license as Perl itself.
11             # -------------------------------------------------------------------------------------
12             package MKDoc::XML::TreeBuilder;
13 8     8   143273 use MKDoc::XML::Tokenizer;
  8         25  
  8         274  
14 8     8   63 use strict;
  8         14  
  8         251  
15 8     8   39 use warnings;
  8         15  
  8         11704  
16              
17              
18             ##
19             # $class->process_data ($xml);
20             # ----------------------------
21             # Parses $xml and turns it into a tree structure very similar
22             # to HTML::Element objects.
23             ##
24             sub process_data
25             {
26 22     22 1 79 my $class = shift;
27 22         156 my $tokens = MKDoc::XML::Tokenizer->process_data (@_);
28 22         83 return _process_recurse ($tokens);
29             }
30              
31              
32             ##
33             # $class->process_file ($filename);
34             # ---------------------------------
35             # Parses $xml and turns it into a tree structure very similar
36             # to HTML::Element objects.
37             ##
38             sub process_file
39             {
40 1     1 0 13 my $class = shift;
41 1         11 my $tokens = MKDoc::XML::Tokenizer->process_file (@_);
42 1         5 return _process_recurse ($tokens);
43             }
44              
45              
46             ##
47             # _process_recurse ($token_list);
48             # -------------------------------
49             # Turns $token_list array ref into a tree structure.
50             ##
51             sub _process_recurse
52             {
53 240     240   376 my $tokens = shift;
54 240         416 my @result = ();
55            
56 240         337 while (@{$tokens})
  873         4957  
57             {
58             # takes the first available token from the $tokens array reference
59 633         686 my $token = shift @{$tokens};
  633         1049  
60 633         797 my $node = undef;
61            
62 633         1727 $node = $token->leaf();
63 633 100       1317 defined $node and do {
64 416         752 push @result, $node;
65 416         894 next;
66             };
67            
68 217         1305 $node = $token->tag_open();
69 217 50       593 defined $node and do {
70 217         480 my $descendants = _descendant_tokens ($token, $tokens);
71 217         1484 $node->{_content} = _process_recurse ($descendants);
72 217         338 push @result, $node;
73 217         547 next;
74             };
75              
76 0         0 my $token_as_string = $token->as_string();
77 0         0 die qq |parse_error: Is this XML well-formed? (unexpected closing tag "$token_as_string")|;
78             }
79            
80 240 100       1044 return wantarray ? @result : \@result;
81             }
82              
83              
84             ##
85             # $class->descendant_tokens ($token, $tokens);
86             # --------------------------------------------
87             # Removes all tokens from $tokens which are descendants
88             # of $token - assuming that $token is an opening tag token.
89             #
90             # Returns all the tokens removed except for $token matching
91             # closing tag. So the closing tag is removed from $tokens
92             # but not returned.
93             ##
94             sub _descendant_tokens
95             {
96 218     218   301 my $token = shift;
97 218         257 my $tokens = shift;
98 218         336 my @res = ();
99 218         257 my $balance = 1;
100 218         265 while (@{$tokens})
  7419         18656  
101             {
102 7419         9703 my $next_token = shift (@{$tokens});
  7419         13160  
103 7419         10226 my $node = undef;
104            
105 7419         22792 $node = $next_token->leaf();
106 7419 100       21021 defined $node and do {
107 3701         13009 push @res, $next_token;
108 3701         6387 next;
109             };
110            
111 3718         16833 $node = $next_token->tag_open();
112 3718 100       10333 defined $node and do {
113 1750         2138 $balance++;
114 1750         2382 push @res, $next_token;
115 1750         5349 next;
116             };
117            
118 1968         5587 $node = $next_token->tag_close();
119 1968 50       4892 defined $node and do {
120 1968         5774 $balance--;
121 1968 100       6956 last if ($balance == 0);
122 1750         3257 push @res, $next_token;
123 1750         4870 next;
124             };
125            
126 0         0 die "BUG: The program should never reach this statement.";
127             }
128            
129 218 50       991 return \@res if ($balance == 0);
130 0           my $token_as_string = $token->as_string();
131 0           die qq |parse_error: Is this XML well-formed? (could not find closing tag for "$token_as_string")|;
132             }
133              
134              
135             1;
136              
137              
138             __END__