dtddoc step 4: Perl code - exploring XML | WebReference

dtddoc step 4: Perl code - exploring XML

dtddoc step 4: Generating HTML

The Perl solution

#!/usr/bin/perl
use strict;
use SGML::DTD;
sub callback {
  local (*comment) = @_;
  if (my @match = (${*comment} =~ /<(\w*)(\s+(\w+)="[^"]*")?>\s*(.*)(\n[\w\W]*)?/m)) {
    $::comments{"$match[0] $match[2]"} = [htmlify_comment($match[3]), htmlify_comment($match[4])];
  }
}
sub write_overview_page {
  my ($fh, $dtd, %comments) = @_;
  write_header($fh);
  print $fh "<h1>DTD Overview</h1>";
  print $fh "<p>$comments{' '}[0]</p>";
  print $fh "<p>$comments{' '}[1]</p>";
  my @top_elements = $dtd->get_top_elements();
  my $root = shift @top_elements;
  print $fh "<h2>Root element</h2><p><a href=elt-$root.html>$root</a></p>";
  write_footer($fh);
}
sub write_tree_page {
  my ($fh, $dtd, %comments) = @_;
  write_header($fh);
  print $fh "<h1>Element Tree</h1>";
  print $fh "<ul>";
  my @top_elements = $dtd->get_top_elements();
  my $root = shift @top_elements;
  write_tree_element($fh, $dtd, $root, %comments);
  print $fh "</ul>";
  write_footer($fh);
}
sub write_tree_element {
  my ($fh, $dtd, $eltName, %comments) = @_;
  print $fh "<li><a href=elt-$eltName.html>$eltName</a>";
  print $fh " - " . $comments{$eltName . ' '}[0];
  my $first = 1;
  foreach my $item ($dtd->get_base_children($eltName)) {
    next if ((substr $item, 0, 1) eq '#');
    if ($first) {
      print $fh "<ul>";
      $first = 0;
    }
    write_tree_element($fh, $dtd, $item, %comments);
  }
  if (!$first) {
    print $fh "</ul>";
  }
}
sub write_index_page {
  my ($fh, $dtd, %comments) = @_;
  write_header($fh);
  print $fh "<h1>Index</h1>";
  my @index;
  foreach my $elt ($dtd->get_elements()) {
    insert_into_index(\@index, $elt, 'Element', $comments{$elt . ' '}[0]);
    foreach my $att ($dtd->get_elem_attr()) {
      insert_into_index(\@index, "$att ($elt)", 'Attribute', $comments{$elt . ' ' . $att}[0]);
    }
  }
  foreach my $ent ($dtd->get_gen_ents()) {
    insert_into_index(\@index, $ent, 'Entity', 'TODO: ent->value');
  }
#  foreach my $not ($dtd->get_notations()) {
#    insert_into_index(\@index, $not->name, 'Notation', $not->externalID->system);
#  }
  print $fh "<table border=1><tr><th>Name</th><th>Type</th><th>Value</th></tr>";
  foreach my $line (sort {uc($a) cmp uc($b)} @index) {
    print $fh "<tr><td>$line</td></tr>";
  }
  print $fh "</table>";
  write_footer($fh);
}
sub insert_into_index {
  my ($indexref, $name, $type, $value) = @_;
  my $sort = "<!--$name-->";
  $sort .= ($type eq 'Element') ? "<a href=elt-$name.html>$name</a>" : $name;
  push @$indexref, "$sort</td><td>$type</td><td>$value";
}
sub write_notations_page {
  my ($fh, $dtd, %comments) = @_;
  write_header($fh);
  print $fh "<h1>Notations</h1>";
#  if (sizeof($dtd->get_notations()) == 0) {
    print $fh "<p><em>TODO: Not supported by SGML::DTD</em></p>";
#  }
#  else {
#    foreach my $not ($dtd->get_notations()) {
#      print $fh "<li>$not = TODO:$not->externalID->system</li>";
#    }
#  }
  write_footer($fh);
}
sub write_entities_page {
  my ($fh, $dtd, %comments) = @_;
  write_header($fh);
  print $fh "<h1>Entities</h1>";
  if (scalar($dtd->get_gen_ents(1)) == 0) {
    print $fh "<p><em>None</em></p>";
  }
  else {
    print $fh "<ul>";
    foreach my $ent (sort {uc($a) cmp uc($b)} $dtd->get_gen_ents(1)) {
      print $fh "<li>$ent = TODO:ent->value</li>";
    }
    print $fh "</ul>";
  }
  write_footer($fh);
}
sub write_element_page {
  my ($fh, $dtd, $elt, %comments) = @_;
  write_header($fh);
  print $fh "<h1>Element <$elt></h1>";
  print $fh "<p>" . $comments{$elt . ' '}[0] . "</p>";
  my $comment = $comments{$elt . ' '}[1];
  if ($comment) {
    print $fh "<p>$comment</p>";
  }
  print $fh "<h2>Attributes</h2>";
  if (!$dtd->get_elem_attr($elt)) {
    print $fh "<p><em>None</em></p>";
  }
  else {
    print $fh "<dl>";
    my %attrs = $dtd->get_elem_attr($elt);
    foreach my $att (keys %attrs) {
      my $value = join(' ', @{$attrs{$att}});
      print $fh "<dt>$att $value</dt>";
      print $fh "<dd>" . $comments{$elt . ' ' . $att}[0] . "</dd>";
    }
    print $fh "</dl>";
  }
  print $fh "<h2>Content</h2>";
  print $fh "<p>" . htmlify_content(join(' ', $dtd->get_base_children($elt, 1))) . "</p>";
  print $fh "<h2>Parents</h2>";
  my @pars = $dtd->get_parents($elt);
  if (!@pars) {
    print $fh "<p><em>None</em></p>";
  }
  else {
    print $fh "<p>";
    foreach my $parent (@pars) {
      print $fh "<a href=elt-$parent.html>$parent</a> ";
    }
    print $fh "</p>";
  }
  write_footer($fh);
}
sub htmlify_content {
  my ($content) = @_;
  $content =~ s! (\w+) ! <a href=elt-$1.html>$1</a> !g;
  return $content;
}
sub htmlify_comment {
  my ($comment) = @_;
  $comment =~ s!<(\w+)>!<a href=elt-$1.html>$1</a>!g;
  $comment =~ s/html://g;
  return $comment;
}
sub write_header {
  my ($fh) = @_;
  print $fh "<html><body><p>";
  print $fh "<a href=dtd-overview.html>Overview</a> ";
  print $fh "<a href=dtd-tree.html>Tree</a> ";
  print $fh "<a href=dtd-index.html>Index</a> ";
  print $fh "<a href=dtd-notations.html>Notations</a> ";
  print $fh "<a href=dtd-entities.html>Entities</a> ";
  print $fh "</p>";
}
sub write_footer {
  my ($fh) = @_;
  print $fh "</body></html>";
  close $fh;
}
our %comments;
open FH, $ARGV[0];
SGML::DTD->set_comment_callback(\&callback);
my $dtd = new SGML::DTD \*FH;
open FH, ">dtd-overview.html";
write_overview_page(\*FH, $dtd, %comments);
open FH, ">dtd-tree.html";
write_tree_page(\*FH, $dtd, %comments);
open FH, ">dtd-index.html";
write_index_page(\*FH, $dtd, %comments);
open FH, ">dtd-notations.html";
write_notations_page(\*FH, $dtd, %comments);
open FH, ">dtd-entities.html";
write_entities_page(\*FH, $dtd, %comments);
foreach my $elt ($dtd->get_elements()) {
  open FH, ">elt-$elt.html";
  write_element_page(\*FH, $dtd, $elt, %comments);
}


Produced by Michael Claßen

URL: http://www.webreference.com/xml/column68/dtddoc.pl.html
Created: Nov 11, 2002
Revised: Nov 11, 2002