| 2 | use strict; | use strict; | 
| 3 |  |  | 
| 4 | use lib qw[/home/httpd/html/www/markup/html/whatpm | use lib qw[/home/httpd/html/www/markup/html/whatpm | 
| 5 | /home/wakaba/work/manakai/lib | /home/wakaba/work/manakai2/lib]; | 
|  | /home/wakaba/public_html/-temp/wiki/lib]; |  | 
| 6 | use CGI::Carp qw[fatalsToBrowser]; | use CGI::Carp qw[fatalsToBrowser]; | 
| 7 | use Scalar::Util qw[refaddr]; | use Scalar::Util qw[refaddr]; | 
| 8 |  | use Time::HiRes qw/time/; | 
|  | use SuikaWiki::Input::HTTP; ## TODO: Use some better CGI module |  | 
| 9 |  |  | 
| 10 | sub htescape ($) { | sub htescape ($) { | 
| 11 | my $s = $_[0]; | my $s = $_[0]; | 
| 19 | return $s; | return $s; | 
| 20 | } # htescape | } # htescape | 
| 21 |  |  | 
| 22 | my $http = SuikaWiki::Input::HTTP->new; | use Message::CGI::HTTP; | 
| 23 |  | my $http = Message::CGI::HTTP->new; | 
|  | ## TODO: _charset_ |  | 
| 24 |  |  | 
| 25 | if ($http->meta_variable ('PATH_INFO') ne '/') { | if ($http->get_meta_variable ('PATH_INFO') ne '/') { | 
| 26 | print STDOUT "Status: 404 Not Found\nContent-Type: text/plain; charset=us-ascii\n\n400"; | print STDOUT "Status: 404 Not Found\nContent-Type: text/plain; charset=us-ascii\n\n400"; | 
| 27 | exit; | exit; | 
| 28 | } | } | 
| 29 |  |  | 
| 30 | binmode STDOUT, ':utf8'; | binmode STDOUT, ':utf8'; | 
| 31 |  | $| = 1; | 
| 32 |  |  | 
| 33 | require Message::DOM::DOMImplementation; | require Message::DOM::DOMImplementation; | 
| 34 | my $dom = Message::DOM::DOMImplementation->new; | my $dom = Message::DOM::DOMImplementation->new; | 
| 35 |  |  | 
|  | my $input = get_input_document ($http, $dom); |  | 
|  | my $inner_html_element = $http->parameter ('e'); |  | 
|  |  |  | 
| 36 | load_text_catalog ('en'); ## TODO: conneg | load_text_catalog ('en'); ## TODO: conneg | 
| 37 |  |  | 
| 38 | my @nav; | my @nav; | 
| 47 | <body> | <body> | 
| 48 | <h1><a href="../cc-interface">Web Document Conformance Checker</a> | <h1><a href="../cc-interface">Web Document Conformance Checker</a> | 
| 49 | (<em>beta</em>)</h1> | (<em>beta</em>)</h1> | 
| 50 |  | ]; | 
| 51 |  |  | 
| 52 |  | $| = 0; | 
| 53 |  | my $input = get_input_document ($http, $dom); | 
| 54 |  | my $inner_html_element = $http->get_parameter ('e'); | 
| 55 |  | my $char_length = 0; | 
| 56 |  | my %time; | 
| 57 |  |  | 
| 58 |  | print qq[ | 
| 59 | <div id="document-info" class="section"> | <div id="document-info" class="section"> | 
| 60 | <dl> | <dl> | 
| 61 | <dt>Request URI</dt> | <dt>Request URI</dt> | 
| 66 | push @nav, ['#document-info' => 'Information']; | push @nav, ['#document-info' => 'Information']; | 
| 67 |  |  | 
| 68 | if (defined $input->{s}) { | if (defined $input->{s}) { | 
| 69 |  | $char_length = length $input->{s}; | 
| 70 |  |  | 
| 71 | print STDOUT qq[ | print STDOUT qq[ | 
| 72 | <dt>Base URI</dt> | <dt>Base URI</dt> | 
| 77 | <dt>Character Encoding</dt> | <dt>Character Encoding</dt> | 
| 78 | <dd>@{[defined $input->{charset} ? '<code class="charset" lang="en">'.htescape ($input->{charset}).'</code>' : '(none)']} | <dd>@{[defined $input->{charset} ? '<code class="charset" lang="en">'.htescape ($input->{charset}).'</code>' : '(none)']} | 
| 79 | @{[$input->{charset_overridden} ? '<em>(overridden)</em>' : '']}</dd> | @{[$input->{charset_overridden} ? '<em>(overridden)</em>' : '']}</dd> | 
| 80 |  | <dt>Length</dt> | 
| 81 |  | <dd>$char_length byte@{[$char_length == 1 ? '' : 's']}</dd> | 
| 82 | </dl> | </dl> | 
| 83 | </div> | </div> | 
| 84 | ]; | ]; | 
| 89 | my $el; | my $el; | 
| 90 |  |  | 
| 91 | if ($input->{media_type} eq 'text/html') { | if ($input->{media_type} eq 'text/html') { | 
| 92 | require Encode; | ($doc, $el) = print_syntax_error_html_section ($input); | 
|  | require Whatpm::HTML; |  | 
|  |  |  | 
|  | $input->{charset} ||= 'ISO-8859-1'; ## TODO: for now. |  | 
|  |  |  | 
|  | my $t = Encode::decode ($input->{charset}, $input->{s}); |  | 
|  |  |  | 
|  | print STDOUT qq[ |  | 
|  | <div id="parse-errors" class="section"> |  | 
|  | <h2>Parse Errors</h2> |  | 
|  |  |  | 
|  | <dl>]; |  | 
|  | push @nav, ['#parse-errors' => 'Parse Error']; |  | 
|  |  |  | 
|  | my $onerror = sub { |  | 
|  | my (%opt) = @_; |  | 
|  | my ($type, $cls, $msg) = get_text ($opt{type}, $opt{level}); |  | 
|  | if ($opt{column} > 0) { |  | 
|  | print STDOUT qq[<dt class="$cls"><a href="#line-$opt{line}">Line $opt{line}</a> column $opt{column}</dt>\n]; |  | 
|  | } else { |  | 
|  | $opt{line} = $opt{line} - 1 || 1; |  | 
|  | print STDOUT qq[<dt class="$cls"><a href="#line-$opt{line}">Line $opt{line}</a></dt>\n]; |  | 
|  | } |  | 
|  | $type =~ tr/ /-/; |  | 
|  | $type =~ s/\|/%7C/g; |  | 
|  | $msg .= qq[ [<a href="../error-description#@{[htescape ($type)]}">Description</a>]]; |  | 
|  | print STDOUT qq[<dd class="$cls">$msg</dd>\n]; |  | 
|  | }; |  | 
|  |  |  | 
|  | $doc = $dom->create_document; |  | 
|  | if (defined $inner_html_element and length $inner_html_element) { |  | 
|  | $el = $doc->create_element_ns |  | 
|  | ('http://www.w3.org/1999/xhtml', [undef, $inner_html_element]); |  | 
|  | Whatpm::HTML->set_inner_html ($el, $t, $onerror); |  | 
|  | } else { |  | 
|  | Whatpm::HTML->parse_string ($t => $doc, $onerror); |  | 
|  | } |  | 
|  |  |  | 
|  | print STDOUT qq[</dl> |  | 
|  | </div> |  | 
|  | ]; |  | 
|  |  |  | 
| 93 | print_source_string_section (\($input->{s}), $input->{charset}); | print_source_string_section (\($input->{s}), $input->{charset}); | 
| 94 | } elsif ({ | } elsif ({ | 
| 95 | 'text/xml' => 1, | 'text/xml' => 1, | 
| 96 |  | 'application/atom+xml' => 1, | 
| 97 |  | 'application/rss+xml' => 1, | 
| 98 |  | 'application/svg+xml' => 1, | 
| 99 | 'application/xhtml+xml' => 1, | 'application/xhtml+xml' => 1, | 
| 100 | 'application/xml' => 1, | 'application/xml' => 1, | 
| 101 | }->{$input->{media_type}}) { | }->{$input->{media_type}}) { | 
| 102 | require Message::DOM::XMLParserTemp; | ($doc, $el) = print_syntax_error_xml_section ($input); | 
|  |  |  | 
|  | print STDOUT qq[ |  | 
|  | <div id="parse-errors" class="section"> |  | 
|  | <h2>Parse Errors</h2> |  | 
|  |  |  | 
|  | <dl>]; |  | 
|  | push @nav, ['#parse-errors' => 'Parse Error']; |  | 
|  |  |  | 
|  | my $onerror = sub { |  | 
|  | my $err = shift; |  | 
|  | my $line = $err->location->line_number; |  | 
|  | print STDOUT qq[<dt><a href="#line-$line">Line $line</a> column ]; |  | 
|  | print STDOUT $err->location->column_number, "</dt><dd>"; |  | 
|  | print STDOUT htescape $err->text, "</dd>\n"; |  | 
|  | return 1; |  | 
|  | }; |  | 
|  |  |  | 
|  | open my $fh, '<', \($input->{s}); |  | 
|  | $doc = Message::DOM::XMLParserTemp->parse_byte_stream |  | 
|  | ($fh => $dom, $onerror, charset => $input->{charset}); |  | 
|  |  |  | 
|  | print STDOUT qq[</dl> |  | 
|  | </div> |  | 
|  |  |  | 
|  | ]; |  | 
| 103 | print_source_string_section (\($input->{s}), $doc->input_encoding); | print_source_string_section (\($input->{s}), $doc->input_encoding); | 
| 104 | } else { | } else { | 
| 105 | ## TODO: Change HTTP status code?? | ## TODO: Change HTTP status code?? | 
| 106 | print STDOUT qq[ | print_result_unknown_type_section ($input); | 
|  | <div id="result-summary" class="section"> |  | 
|  | <p><em>Media type <code class="MIME" lang="en">@{[htescape $input->{media_type}]}</code> is not supported!</em></p> |  | 
|  | </div> |  | 
|  | ]; |  | 
|  | push @nav, ['#result-summary' => 'Result']; |  | 
| 107 | } | } | 
| 108 |  |  | 
|  |  |  | 
| 109 | if (defined $doc or defined $el) { | if (defined $doc or defined $el) { | 
| 110 | print STDOUT qq[ | print_structure_dump_section ($doc, $el); | 
| 111 | <div id="document-tree" class="section"> | my $elements = print_structure_error_section ($doc, $el); | 
| 112 | <h2>Document Tree</h2> | print_table_section ($elements->{table}) if @{$elements->{table}}; | 
| 113 | ]; | print_id_section ($elements->{id}) if keys %{$elements->{id}}; | 
| 114 | push @nav, ['#document-tree' => 'Tree']; | print_term_section ($elements->{term}) if keys %{$elements->{term}}; | 
| 115 |  | print_class_section ($elements->{class}) if keys %{$elements->{class}}; | 
|  | print_document_tree ($el || $doc); |  | 
|  |  |  | 
|  | print STDOUT qq[ |  | 
|  | </div> |  | 
|  |  |  | 
|  | <div id="document-errors" class="section"> |  | 
|  | <h2>Document Errors</h2> |  | 
|  |  |  | 
|  | <dl>]; |  | 
|  | push @nav, ['#document-errors' => 'Document Error']; |  | 
|  |  |  | 
|  | require Whatpm::ContentChecker; |  | 
|  | my $onerror = sub { |  | 
|  | my %opt = @_; |  | 
|  | my ($type, $cls, $msg) = get_text ($opt{type}, $opt{level}); |  | 
|  | $type =~ tr/ /-/; |  | 
|  | $type =~ s/\|/%7C/g; |  | 
|  | $msg .= qq[ [<a href="../error-description#@{[htescape ($type)]}">Description</a>]]; |  | 
|  | print STDOUT qq[<dt class="$cls">] . get_node_link ($opt{node}) . |  | 
|  | qq[</dt>\n<dd class="$cls">], $msg, "</dd>\n"; |  | 
|  | }; |  | 
|  |  |  | 
|  | my $elements; |  | 
|  | if ($el) { |  | 
|  | $elements = Whatpm::ContentChecker->check_element ($el, $onerror); |  | 
|  | } else { |  | 
|  | $elements = Whatpm::ContentChecker->check_document ($doc, $onerror); |  | 
|  | } |  | 
|  |  |  | 
|  | print STDOUT qq[</dl> |  | 
|  | </div> |  | 
|  | ]; |  | 
|  |  |  | 
|  | if (@{$elements->{table}}) { |  | 
|  | require JSON; |  | 
|  |  |  | 
|  | print STDOUT qq[ |  | 
|  | <div id="tables" class="section"> |  | 
|  | <h2>Tables</h2> |  | 
|  |  |  | 
|  | <!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]--> |  | 
|  | <script src="../table-script.js" type="text/javascript"></script> |  | 
|  | <noscript> |  | 
|  | <p><em>Structure of tables are visualized here if scripting is enabled.</em></p> |  | 
|  | </noscript> |  | 
|  | ]; |  | 
|  |  |  | 
|  | my $i = 0; |  | 
|  | for my $table_el (@{$elements->{table}}) { |  | 
|  | $i++; |  | 
|  | print STDOUT qq[<div class="section" id="table-$i"><h3>] . |  | 
|  | get_node_link ($table_el) . q[</h3>]; |  | 
|  |  |  | 
|  | ## TODO: Make |ContentChecker| return |form_table| result |  | 
|  | ## so that this script don't have to run the algorithm twice. |  | 
|  | my $table = Whatpm::HTMLTable->form_table ($table_el); |  | 
|  |  |  | 
|  | for (@{$table->{column_group}}, @{$table->{column}}, $table->{caption}) { |  | 
|  | next unless $_; |  | 
|  | delete $_->{element}; |  | 
|  | } |  | 
|  |  |  | 
|  | for (@{$table->{row_group}}) { |  | 
|  | next unless $_; |  | 
|  | next unless $_->{element}; |  | 
|  | $_->{type} = $_->{element}->manakai_local_name; |  | 
|  | delete $_->{element}; |  | 
|  | } |  | 
|  |  |  | 
|  | for (@{$table->{cell}}) { |  | 
|  | next unless $_; |  | 
|  | for (@{$_}) { |  | 
|  | next unless $_; |  | 
|  | for (@$_) { |  | 
|  | $_->{id} = refaddr $_->{element} if defined $_->{element}; |  | 
|  | delete $_->{element}; |  | 
|  | $_->{is_header} = $_->{is_header} ? 1 : 0; |  | 
|  | } |  | 
|  | } |  | 
|  | } |  | 
|  |  |  | 
|  | print STDOUT '</div><script type="text/javascript">tableToCanvas ('; |  | 
|  | print STDOUT JSON::objToJson ($table); |  | 
|  | print STDOUT qq[, document.getElementById ('table-$i'));</script>]; |  | 
|  | } |  | 
|  |  |  | 
|  | print STDOUT qq[</div>]; |  | 
|  | } |  | 
|  |  |  | 
|  | if (keys %{$elements->{id}}) { |  | 
|  | print STDOUT qq[ |  | 
|  | <div id="identifiers" class="section"> |  | 
|  | <h2>Identifiers</h2> |  | 
|  |  |  | 
|  | <dl> |  | 
|  | ]; |  | 
|  | for my $id (sort {$a cmp $b} keys %{$elements->{id}}) { |  | 
|  | print STDOUT qq[<dt>@{[htescape $id]}</dt>]; |  | 
|  | for (@{$elements->{id}->{$id}}) { |  | 
|  | print STDOUT qq[<dd>].get_node_link ($_).qq[</dd>]; |  | 
|  | } |  | 
|  | } |  | 
|  | print STDOUT qq[</dl></div>]; |  | 
|  | } |  | 
|  |  |  | 
|  | if (keys %{$elements->{term}}) { |  | 
|  | print STDOUT qq[ |  | 
|  | <div id="terms" class="section"> |  | 
|  | <h2>Terms</h2> |  | 
|  |  |  | 
|  | <dl> |  | 
|  | ]; |  | 
|  | for my $term (sort {$a cmp $b} keys %{$elements->{term}}) { |  | 
|  | print STDOUT qq[<dt>@{[htescape $term]}</dt>]; |  | 
|  | for (@{$elements->{term}->{$term}}) { |  | 
|  | print STDOUT qq[<dd>].get_node_link ($_).qq[</dd>]; |  | 
|  | } |  | 
|  | } |  | 
|  | print STDOUT qq[</dl></div>]; |  | 
|  | } |  | 
| 116 | } | } | 
| 117 |  |  | 
| 118 | ## TODO: Show result | ## TODO: Show result | 
| 119 | } else { | } else { | 
| 120 | print STDOUT qq[ | print STDOUT qq[</dl></div>]; | 
| 121 | </dl> | print_result_input_error_section ($input); | 
|  | </div> |  | 
|  |  |  | 
|  | <div class="section" id="result-summary"> |  | 
|  | <p><em><strong>Input Error</strong>: @{[htescape ($input->{error_status_text})]}</em></p> |  | 
|  | </div> |  | 
|  | ]; |  | 
|  | push @nav, ['#result-summary' => 'Result']; |  | 
|  |  |  | 
| 122 | } | } | 
| 123 |  |  | 
| 124 | print STDOUT qq[ | print STDOUT qq[ | 
| 133 | </html> | </html> | 
| 134 | ]; | ]; | 
| 135 |  |  | 
| 136 |  | for (qw/decode parse parse_xml check/) { | 
| 137 |  | next unless defined $time{$_}; | 
| 138 |  | open my $file, '>>', ".cc-$_.txt" or die ".cc-$_.txt: $!"; | 
| 139 |  | print $file $char_length, "\t", $time{$_}, "\n"; | 
| 140 |  | } | 
| 141 |  |  | 
| 142 | exit; | exit; | 
| 143 |  |  | 
| 144 | sub print_http_header_section ($) { | sub print_http_header_section ($) { | 
| 175 | print STDOUT qq[</tbody></table></div>]; | print STDOUT qq[</tbody></table></div>]; | 
| 176 | } # print_http_header_section | } # print_http_header_section | 
| 177 |  |  | 
| 178 |  | sub print_syntax_error_html_section ($) { | 
| 179 |  | my $input = shift; | 
| 180 |  |  | 
| 181 |  | require Encode; | 
| 182 |  | require Whatpm::HTML; | 
| 183 |  |  | 
| 184 |  | $input->{charset} ||= 'ISO-8859-1'; ## TODO: for now. | 
| 185 |  |  | 
| 186 |  | my $time1 = time; | 
| 187 |  | my $t = Encode::decode ($input->{charset}, $input->{s}); | 
| 188 |  | $time{decode} = time - $time1; | 
| 189 |  |  | 
| 190 |  | print STDOUT qq[ | 
| 191 |  | <div id="parse-errors" class="section"> | 
| 192 |  | <h2>Parse Errors</h2> | 
| 193 |  |  | 
| 194 |  | <dl>]; | 
| 195 |  | push @nav, ['#parse-errors' => 'Parse Error']; | 
| 196 |  |  | 
| 197 |  | my $onerror = sub { | 
| 198 |  | my (%opt) = @_; | 
| 199 |  | my ($type, $cls, $msg) = get_text ($opt{type}, $opt{level}); | 
| 200 |  | if ($opt{column} > 0) { | 
| 201 |  | print STDOUT qq[<dt class="$cls"><a href="#line-$opt{line}">Line $opt{line}</a> column $opt{column}</dt>\n]; | 
| 202 |  | } else { | 
| 203 |  | $opt{line} = $opt{line} - 1 || 1; | 
| 204 |  | print STDOUT qq[<dt class="$cls"><a href="#line-$opt{line}">Line $opt{line}</a></dt>\n]; | 
| 205 |  | } | 
| 206 |  | $type =~ tr/ /-/; | 
| 207 |  | $type =~ s/\|/%7C/g; | 
| 208 |  | $msg .= qq[ [<a href="../error-description#@{[htescape ($type)]}">Description</a>]]; | 
| 209 |  | print STDOUT qq[<dd class="$cls">$msg</dd>\n]; | 
| 210 |  | }; | 
| 211 |  |  | 
| 212 |  | my $doc = $dom->create_document; | 
| 213 |  | my $el; | 
| 214 |  | $time1 = time; | 
| 215 |  | if (defined $inner_html_element and length $inner_html_element) { | 
| 216 |  | $el = $doc->create_element_ns | 
| 217 |  | ('http://www.w3.org/1999/xhtml', [undef, $inner_html_element]); | 
| 218 |  | Whatpm::HTML->set_inner_html ($el, $t, $onerror); | 
| 219 |  | } else { | 
| 220 |  | Whatpm::HTML->parse_string ($t => $doc, $onerror); | 
| 221 |  | } | 
| 222 |  | $time{parse} = time - $time1; | 
| 223 |  |  | 
| 224 |  | print STDOUT qq[</dl></div>]; | 
| 225 |  |  | 
| 226 |  | return ($doc, $el); | 
| 227 |  | } # print_syntax_error_html_section | 
| 228 |  |  | 
| 229 |  | sub print_syntax_error_xml_section ($) { | 
| 230 |  | my $input = shift; | 
| 231 |  |  | 
| 232 |  | require Message::DOM::XMLParserTemp; | 
| 233 |  |  | 
| 234 |  | print STDOUT qq[ | 
| 235 |  | <div id="parse-errors" class="section"> | 
| 236 |  | <h2>Parse Errors</h2> | 
| 237 |  |  | 
| 238 |  | <dl>]; | 
| 239 |  | push @nav, ['#parse-errors' => 'Parse Error']; | 
| 240 |  |  | 
| 241 |  | my $onerror = sub { | 
| 242 |  | my $err = shift; | 
| 243 |  | my $line = $err->location->line_number; | 
| 244 |  | print STDOUT qq[<dt><a href="#line-$line">Line $line</a> column ]; | 
| 245 |  | print STDOUT $err->location->column_number, "</dt><dd>"; | 
| 246 |  | print STDOUT htescape $err->text, "</dd>\n"; | 
| 247 |  | return 1; | 
| 248 |  | }; | 
| 249 |  |  | 
| 250 |  | my $time1 = time; | 
| 251 |  | open my $fh, '<', \($input->{s}); | 
| 252 |  | my $doc = Message::DOM::XMLParserTemp->parse_byte_stream | 
| 253 |  | ($fh => $dom, $onerror, charset => $input->{charset}); | 
| 254 |  | $time{parse_xml} = time - $time1; | 
| 255 |  |  | 
| 256 |  | print STDOUT qq[</dl></div>]; | 
| 257 |  |  | 
| 258 |  | return ($doc, undef); | 
| 259 |  | } # print_syntax_error_xml_section | 
| 260 |  |  | 
| 261 | sub print_source_string_section ($$) { | sub print_source_string_section ($$) { | 
| 262 | require Encode; | require Encode; | 
| 263 | my $enc = Encode::find_encoding ($_[1]); ## TODO: charset name -> Perl name | my $enc = Encode::find_encoding ($_[1]); ## TODO: charset name -> Perl name | 
| 360 | print STDOUT $r; | print STDOUT $r; | 
| 361 | } # print_document_tree | } # print_document_tree | 
| 362 |  |  | 
| 363 |  | sub print_structure_dump_section ($$) { | 
| 364 |  | my ($doc, $el) = @_; | 
| 365 |  |  | 
| 366 |  | print STDOUT qq[ | 
| 367 |  | <div id="document-tree" class="section"> | 
| 368 |  | <h2>Document Tree</h2> | 
| 369 |  | ]; | 
| 370 |  | push @nav, ['#document-tree' => 'Tree']; | 
| 371 |  |  | 
| 372 |  | print_document_tree ($el || $doc); | 
| 373 |  |  | 
| 374 |  | print STDOUT qq[</div>]; | 
| 375 |  | } # print_structure_dump_section | 
| 376 |  |  | 
| 377 |  | sub print_structure_error_section ($$) { | 
| 378 |  | my ($doc, $el) = @_; | 
| 379 |  |  | 
| 380 |  | print STDOUT qq[<div id="document-errors" class="section"> | 
| 381 |  | <h2>Document Errors</h2> | 
| 382 |  |  | 
| 383 |  | <dl>]; | 
| 384 |  | push @nav, ['#document-errors' => 'Document Error']; | 
| 385 |  |  | 
| 386 |  | require Whatpm::ContentChecker; | 
| 387 |  | my $onerror = sub { | 
| 388 |  | my %opt = @_; | 
| 389 |  | my ($type, $cls, $msg) = get_text ($opt{type}, $opt{level}, $opt{node}); | 
| 390 |  | $type =~ tr/ /-/; | 
| 391 |  | $type =~ s/\|/%7C/g; | 
| 392 |  | $msg .= qq[ [<a href="../error-description#@{[htescape ($type)]}">Description</a>]]; | 
| 393 |  | print STDOUT qq[<dt class="$cls">] . get_node_link ($opt{node}) . | 
| 394 |  | qq[</dt>\n<dd class="$cls">], $msg, "</dd>\n"; | 
| 395 |  | }; | 
| 396 |  |  | 
| 397 |  | my $elements; | 
| 398 |  | my $time1 = time; | 
| 399 |  | if ($el) { | 
| 400 |  | $elements = Whatpm::ContentChecker->check_element ($el, $onerror); | 
| 401 |  | } else { | 
| 402 |  | $elements = Whatpm::ContentChecker->check_document ($doc, $onerror); | 
| 403 |  | } | 
| 404 |  | $time{check} = time - $time1; | 
| 405 |  |  | 
| 406 |  | print STDOUT qq[</dl></div>]; | 
| 407 |  |  | 
| 408 |  | return $elements; | 
| 409 |  | } # print_structure_error_section | 
| 410 |  |  | 
| 411 |  | sub print_table_section ($) { | 
| 412 |  | my $tables = shift; | 
| 413 |  |  | 
| 414 |  | push @nav, ['#tables' => 'Tables']; | 
| 415 |  | print STDOUT qq[ | 
| 416 |  | <div id="tables" class="section"> | 
| 417 |  | <h2>Tables</h2> | 
| 418 |  |  | 
| 419 |  | <!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]--> | 
| 420 |  | <script src="../table-script.js" type="text/javascript"></script> | 
| 421 |  | <noscript> | 
| 422 |  | <p><em>Structure of tables are visualized here if scripting is enabled.</em></p> | 
| 423 |  | </noscript> | 
| 424 |  | ]; | 
| 425 |  |  | 
| 426 |  | require JSON; | 
| 427 |  |  | 
| 428 |  | my $i = 0; | 
| 429 |  | for my $table_el (@$tables) { | 
| 430 |  | $i++; | 
| 431 |  | print STDOUT qq[<div class="section" id="table-$i"><h3>] . | 
| 432 |  | get_node_link ($table_el) . q[</h3>]; | 
| 433 |  |  | 
| 434 |  | ## TODO: Make |ContentChecker| return |form_table| result | 
| 435 |  | ## so that this script don't have to run the algorithm twice. | 
| 436 |  | my $table = Whatpm::HTMLTable->form_table ($table_el); | 
| 437 |  |  | 
| 438 |  | for (@{$table->{column_group}}, @{$table->{column}}, $table->{caption}) { | 
| 439 |  | next unless $_; | 
| 440 |  | delete $_->{element}; | 
| 441 |  | } | 
| 442 |  |  | 
| 443 |  | for (@{$table->{row_group}}) { | 
| 444 |  | next unless $_; | 
| 445 |  | next unless $_->{element}; | 
| 446 |  | $_->{type} = $_->{element}->manakai_local_name; | 
| 447 |  | delete $_->{element}; | 
| 448 |  | } | 
| 449 |  |  | 
| 450 |  | for (@{$table->{cell}}) { | 
| 451 |  | next unless $_; | 
| 452 |  | for (@{$_}) { | 
| 453 |  | next unless $_; | 
| 454 |  | for (@$_) { | 
| 455 |  | $_->{id} = refaddr $_->{element} if defined $_->{element}; | 
| 456 |  | delete $_->{element}; | 
| 457 |  | $_->{is_header} = $_->{is_header} ? 1 : 0; | 
| 458 |  | } | 
| 459 |  | } | 
| 460 |  | } | 
| 461 |  |  | 
| 462 |  | print STDOUT '</div><script type="text/javascript">tableToCanvas ('; | 
| 463 |  | print STDOUT JSON::objToJson ($table); | 
| 464 |  | print STDOUT qq[, document.getElementById ('table-$i'));</script>]; | 
| 465 |  | } | 
| 466 |  |  | 
| 467 |  | print STDOUT qq[</div>]; | 
| 468 |  | } # print_table_section | 
| 469 |  |  | 
| 470 |  | sub print_id_section ($) { | 
| 471 |  | my $ids = shift; | 
| 472 |  |  | 
| 473 |  | push @nav, ['#identifiers' => 'IDs']; | 
| 474 |  | print STDOUT qq[ | 
| 475 |  | <div id="identifiers" class="section"> | 
| 476 |  | <h2>Identifiers</h2> | 
| 477 |  |  | 
| 478 |  | <dl> | 
| 479 |  | ]; | 
| 480 |  | for my $id (sort {$a cmp $b} keys %$ids) { | 
| 481 |  | print STDOUT qq[<dt><code>@{[htescape $id]}</code></dt>]; | 
| 482 |  | for (@{$ids->{$id}}) { | 
| 483 |  | print STDOUT qq[<dd>].get_node_link ($_).qq[</dd>]; | 
| 484 |  | } | 
| 485 |  | } | 
| 486 |  | print STDOUT qq[</dl></div>]; | 
| 487 |  | } # print_id_section | 
| 488 |  |  | 
| 489 |  | sub print_term_section ($) { | 
| 490 |  | my $terms = shift; | 
| 491 |  |  | 
| 492 |  | push @nav, ['#terms' => 'Terms']; | 
| 493 |  | print STDOUT qq[ | 
| 494 |  | <div id="terms" class="section"> | 
| 495 |  | <h2>Terms</h2> | 
| 496 |  |  | 
| 497 |  | <dl> | 
| 498 |  | ]; | 
| 499 |  | for my $term (sort {$a cmp $b} keys %$terms) { | 
| 500 |  | print STDOUT qq[<dt>@{[htescape $term]}</dt>]; | 
| 501 |  | for (@{$terms->{$term}}) { | 
| 502 |  | print STDOUT qq[<dd>].get_node_link ($_).qq[</dd>]; | 
| 503 |  | } | 
| 504 |  | } | 
| 505 |  | print STDOUT qq[</dl></div>]; | 
| 506 |  | } # print_term_section | 
| 507 |  |  | 
| 508 |  | sub print_class_section ($) { | 
| 509 |  | my $classes = shift; | 
| 510 |  |  | 
| 511 |  | push @nav, ['#classes' => 'Classes']; | 
| 512 |  | print STDOUT qq[ | 
| 513 |  | <div id="classes" class="section"> | 
| 514 |  | <h2>Classes</h2> | 
| 515 |  |  | 
| 516 |  | <dl> | 
| 517 |  | ]; | 
| 518 |  | for my $class (sort {$a cmp $b} keys %$classes) { | 
| 519 |  | print STDOUT qq[<dt><code>@{[htescape $class]}</code></dt>]; | 
| 520 |  | for (@{$classes->{$class}}) { | 
| 521 |  | print STDOUT qq[<dd>].get_node_link ($_).qq[</dd>]; | 
| 522 |  | } | 
| 523 |  | } | 
| 524 |  | print STDOUT qq[</dl></div>]; | 
| 525 |  | } # print_class_section | 
| 526 |  |  | 
| 527 |  | sub print_result_unknown_type_section ($) { | 
| 528 |  | my $input = shift; | 
| 529 |  |  | 
| 530 |  | print STDOUT qq[ | 
| 531 |  | <div id="result-summary" class="section"> | 
| 532 |  | <p><em>Media type <code class="MIME" lang="en">@{[htescape $input->{media_type}]}</code> is not supported!</em></p> | 
| 533 |  | </div> | 
| 534 |  | ]; | 
| 535 |  | push @nav, ['#result-summary' => 'Result']; | 
| 536 |  | } # print_result_unknown_type_section | 
| 537 |  |  | 
| 538 |  | sub print_result_input_error_section ($) { | 
| 539 |  | my $input = shift; | 
| 540 |  | print STDOUT qq[<div class="section" id="result-summary"> | 
| 541 |  | <p><em><strong>Input Error</strong>: @{[htescape ($input->{error_status_text})]}</em></p> | 
| 542 |  | </div>]; | 
| 543 |  | push @nav, ['#result-summary' => 'Result']; | 
| 544 |  | } # print_Result_input_error_section | 
| 545 |  |  | 
| 546 | sub get_node_path ($) { | sub get_node_path ($) { | 
| 547 | my $node = shift; | my $node = shift; | 
| 548 | my @r; | my @r; | 
| 591 | } # load_text_catalog | } # load_text_catalog | 
| 592 |  |  | 
| 593 | sub get_text ($) { | sub get_text ($) { | 
| 594 | my ($type, $level) = @_; | my ($type, $level, $node) = @_; | 
| 595 | $type = $level . ':' . $type if defined $level; | $type = $level . ':' . $type if defined $level; | 
| 596 | my @arg; | my @arg; | 
| 597 | { | { | 
| 600 | $msg =~ s{<var>\$([0-9]+)</var>}{ | $msg =~ s{<var>\$([0-9]+)</var>}{ | 
| 601 | defined $arg[$1] ? htescape ($arg[$1]) : '(undef)'; | defined $arg[$1] ? htescape ($arg[$1]) : '(undef)'; | 
| 602 | }ge; | }ge; | 
| 603 |  | $msg =~ s{<var>{\@([A-Za-z0-9:_.-]+)}</var>}{ | 
| 604 |  | UNIVERSAL::can ($node, 'get_attribute_ns') | 
| 605 |  | ? htescape ($node->get_attribute_ns (undef, $1)) : '' | 
| 606 |  | }ge; | 
| 607 |  | $msg =~ s{<var>{\@}</var>}{ | 
| 608 |  | UNIVERSAL::can ($node, 'value') ? htescape ($node->value) : '' | 
| 609 |  | }ge; | 
| 610 |  | $msg =~ s{<var>{local-name}</var>}{ | 
| 611 |  | UNIVERSAL::can ($node, 'manakai_local_name') | 
| 612 |  | ? htescape ($node->manakai_local_name) : '' | 
| 613 |  | }ge; | 
| 614 |  | $msg =~ s{<var>{element-local-name}</var>}{ | 
| 615 |  | (UNIVERSAL::can ($node, 'owner_element') and | 
| 616 |  | $node->owner_element) | 
| 617 |  | ? htescape ($node->owner_element->manakai_local_name) | 
| 618 |  | : '' | 
| 619 |  | }ge; | 
| 620 | return ($type, $Msg->{$type}->[0], $msg); | return ($type, $Msg->{$type}->[0], $msg); | 
| 621 | } elsif ($type =~ s/:([^:]*)$//) { | } elsif ($type =~ s/:([^:]*)$//) { | 
| 622 | unshift @arg, $1; | unshift @arg, $1; | 
| 631 | sub get_input_document ($$) { | sub get_input_document ($$) { | 
| 632 | my ($http, $dom) = @_; | my ($http, $dom) = @_; | 
| 633 |  |  | 
| 634 | my $request_uri = $http->parameter ('uri'); | my $request_uri = $http->get_parameter ('uri'); | 
| 635 | my $r = {}; | my $r = {}; | 
| 636 | if (defined $request_uri and length $request_uri) { | if (defined $request_uri and length $request_uri) { | 
| 637 | my $uri = $dom->create_uri_reference ($request_uri); | my $uri = $dom->create_uri_reference ($request_uri); | 
| 680 | $ua->max_size (1000_000); | $ua->max_size (1000_000); | 
| 681 | my $req = HTTP::Request->new (GET => $request_uri); | my $req = HTTP::Request->new (GET => $request_uri); | 
| 682 | my $res = $ua->request ($req); | my $res = $ua->request ($req); | 
| 683 | if ($res->is_success or $http->parameter ('error-page')) { | ## TODO: 401 sets |is_success| true. | 
| 684 |  | if ($res->is_success or $http->get_parameter ('error-page')) { | 
| 685 | $r->{base_uri} = $res->base; ## NOTE: It does check |Content-Base|, |Content-Location|, and <base>. ## TODO: Use our own code! | $r->{base_uri} = $res->base; ## NOTE: It does check |Content-Base|, |Content-Location|, and <base>. ## TODO: Use our own code! | 
| 686 | $r->{uri} = $res->request->uri; | $r->{uri} = $res->request->uri; | 
| 687 | $r->{request_uri} = $request_uri; | $r->{request_uri} = $request_uri; | 
| 696 | $r->{charset} =~ tr/\\//d; | $r->{charset} =~ tr/\\//d; | 
| 697 | } | } | 
| 698 |  |  | 
| 699 | my $input_charset = $http->parameter ('charset'); | my $input_charset = $http->get_parameter ('charset'); | 
| 700 | if (defined $input_charset and length $input_charset) { | if (defined $input_charset and length $input_charset) { | 
| 701 | $r->{charset_overridden} | $r->{charset_overridden} | 
| 702 | = (not defined $r->{charset} or $r->{charset} ne $input_charset); | = (not defined $r->{charset} or $r->{charset} ne $input_charset); | 
| 717 | $r->{header_status_code} = $res->code; | $r->{header_status_code} = $res->code; | 
| 718 | $r->{header_status_text} = $res->message; | $r->{header_status_text} = $res->message; | 
| 719 | } else { | } else { | 
| 720 | $r->{s} = ''.$http->parameter ('s'); | $r->{s} = ''.$http->get_parameter ('s'); | 
| 721 | $r->{uri} = q<thismessage:/>; | $r->{uri} = q<thismessage:/>; | 
| 722 | $r->{request_uri} = q<thismessage:/>; | $r->{request_uri} = q<thismessage:/>; | 
| 723 | $r->{base_uri} = q<thismessage:/>; | $r->{base_uri} = q<thismessage:/>; | 
| 724 | $r->{charset} = ''.$http->parameter ('_charset_'); | $r->{charset} = ''.$http->get_parameter ('_charset_'); | 
| 725 | $r->{charset} =~ s/\s+//g; | $r->{charset} =~ s/\s+//g; | 
| 726 | $r->{charset} = 'utf-8' if $r->{charset} eq ''; | $r->{charset} = 'utf-8' if $r->{charset} eq ''; | 
| 727 | $r->{header_field} = []; | $r->{header_field} = []; | 
| 728 | } | } | 
| 729 |  |  | 
| 730 | my $input_format = $http->parameter ('i'); | my $input_format = $http->get_parameter ('i'); | 
| 731 | if (defined $input_format and length $input_format) { | if (defined $input_format and length $input_format) { | 
| 732 | $r->{media_type_overridden} | $r->{media_type_overridden} | 
| 733 | = (not defined $r->{media_type} or $input_format ne $r->{media_type}); | = (not defined $r->{media_type} or $input_format ne $r->{media_type}); |