# dtdformat module for RefEntrys
# $Id: refentry.pl,v 2.1 2005/07/02 23:51:18 ehood Exp $
use SGML::DTDParse::Util qw(entify);
$fileext = ".xml";
$config{'expanded-element-index'} = "elements";
$config{'unexpanded-element-index'} = "dtdelem";
$config{'expanded-entity-index'} = "entities";
$config{'unexpanded-entity-index'} = "dtdent";
$config{'notation-index'} = 'notations';
# ======================================================================
my $dtdparseHomepage = "http://sourceforge.net/projects/dtdparse/";
# ======================================================================
sub elementRefpurpose {
my $count = shift;
my $name = $elements[$count];
return "&$baseid.purp.elem.$name;";
}
sub entityRefpurpose {
my $count = shift;
my $name = $entities[$count];
my $entity = $entities{$name};
return "&$baseid.purp." . $entity->getAttribute('type') . ".$name;";
}
sub notationRefpurpose {
my $count = shift;
my $name = $notations[$count];
return "&$baseid.purp.notn.$name;";
}
sub elementDescription {
my $count = shift;
return "desc\n";
}
sub entityDescription {
my $count = shift;
return "desc\n";
}
sub notationDescription {
my $count = shift;
return "desc\n";
}
# ======================================================================
sub basenames {
my @names = @_;
my %basename = ();
my %usedname = ();
foreach my $name (@names) {
my $count = 2;
my $bname = lc($name);
if ($usedname{$bname}) {
$bname = lc($name) . $count;
while ($usedname{$bname}) {
$bname++;
}
}
$basename{$name} = $bname;
$usedname{$name} = 1;
}
return %basename;
}
# ======================================================================
sub formatElement {
my $count = shift;
my $html = "";
my $name = $elements[$count];
my $element = $elements{$name};
my $cmex = undef;
my $cmunx = undef;
my $incl = undef;
my $excl = undef;
my $node = $element->getFirstChild();
while ($node) {
if ($node->getNodeType() == XML::DOM::ELEMENT_NODE) {
$cmex = $node if $node->getTagName() eq 'content-model-expanded';
$cmunx = $node if $node->getTagName() eq 'content-model';
$incl = $node if $node->getTagName() eq 'inclusions';
$excl = $node if $node->getTagName() eq 'exclusions';
}
$node = $node->getNextSibling();
}
$html .= &formatElementHeader($count);
$html .= &formatElementTitle($count);
if ($option{'synopsis'}) {
if ($expanded eq 'expanded') {
$html .= &formatElementSynopsis($count, $cmex, $cmex);
} else {
$html .= &formatElementSynopsis($count, $cmunx, $cmex);
}
}
$html .= &formatElementDescription($count, $count)
if $option{'description'};
$html .= &formatElementExamples($count, $count) if $option{'examples'};
$html .= &formatElementFooter($count);
}
sub formatElementHeader {
my $count = shift;
my $html = "";
my $name = $elements[$count];
my $element = $elements{$name};
$html .= "\n";
$html .= "\n";
$html .= "\n\n";
return $html;
}
sub formatElementTitle {
my $count = shift;
my $name = $elements[$count];
my $element = $elements{$name};
my $html = "";
$html .= "\n";
$html .= "";
$html .= $element->getAttribute('name');
$html .= "\n";
$html .= "Element\n";
$html .= "\n\n";
$html .= "\n";
$html .= "" . $element->getAttribute('name') . "\n";
$html .= "";
$html .= &elementRefpurpose($count);
$html .= "\n";
$html .= "\n\n";
}
sub formatElementSynopsis {
my $count = shift;
my $name = $elements[$count];
my $element = $elements{$name};
my $cm = shift;
my $cmex = shift;
my $html = "";
# What are the possibilities: mixed content, element content, or
# declared content...
my $mixed = $element->getAttribute('content-type') eq 'mixed';
my $declared = (!$mixed &&
$element->getAttribute('content-type') ne 'element');
$html .= "\n";
$html .= "\n";
$html .= "\n";
$html .= "\n";
$html .= "\n";
$html .= "\n";
$html .= "\n";
$html .= "\n";
$html .= "getAttribute('name') . " ::=\n";
$html .= &formatContentModel($count, $cm);
$html .= "\n";
$html .= "
\n";
$html .= &formatInclusions($count, $incl)
if $incl && $option{'inclusions'};
$html .= &formatExclusions($count, $excl)
if $excl && $option{'exclusions'};
$html .= &formatAttributeList($count) if $option{'attributes'};
$html .= &formatTagMinimization($count) if $option{'tag-minimization'};
$html .= &formatElementAppearsIn($count) if $option{'appears-in'};
$html .= "\n";
$html .= "\n";
$html .= "\n";
$html .= "\n\n";
return $html;
}
sub formatInclusions {
my $count = shift;
my $cm = shift;
my $name = $elements[$count];
my $element = $elements{$name};
my $html = "";
$html .= "\n";
$html .= "getElementsByTagName("attribute");
for (my $count = 0; $count < $attrs->getLength(); $count++) {
my $attr = $attrs->item($count);
my $name = $attr->getAttribute('name');
my $type = $attr->getAttribute('value');
my $decltype = $attr->getAttribute('type');
my $default = "";
if ($decltype eq '#IMPLIED') {
$default = "None";
} elsif ($decltype eq '#REQUIRED') {
$default = "Required";
} elsif ($decltype eq '#CONREF') {
$default = "Content reference";
} else {
$default = $attr->getAttribute('default');
if ($default =~ /\"/) {
$default = "'" . $default . "'";
} else {
$default = "\"" . $default . "\"";
}
}
if ($decltype eq '#FIXED') {
$default = $default . " (fixed)";
}
$html .= "\n";
$html .= &formatCell($name);
$html .= &formatValues($type, $attr);
$html .= &formatCell($default);
$html .= "
\n";
}
return $html;
}
sub formatCell {
my $value = shift;
return "$value\n";
}
sub formatValues {
my $values = shift;
my $attr = shift;
my $enum = $attr->getAttribute('enumeration');
my $html = "";
if ($enum eq 'no' || $enum eq '') {
return &formatCell($values);
}
$html .= "";
if ($enum eq 'notation') {
$html .= "Enumerated notation:\n";
} else {
$html .= "Enumeration:\n";
}
$html .= "\n";
foreach my $val (sort { uc($a) cmp uc($b) }
split(/\s+/, $attr->getAttribute('value'))) {
$html .= "$val\n";
}
$html .= "\n";
return $html;
}
sub formatTagMinimization {
my $count = shift;
my $name = $elements[$count];
my $element = $elements{$name};
my $html = "";
my $stagm = $element->getAttribute('stagm') || "-";
my $etagm = $element->getAttribute('etagm') || "-";
if ($element->getAttribute('stagm')
|| $element->getAttribute('etagm')) {
my (%min) = ('--' => "Both the start- and end-tags are required for this element.",
'OO' => "Both the start- and end-tags are optional for this element, if your SGML declaration allows tag minimization.",
'O-' => "The start-tag is optional for this element, if your SGML declaration allows tag minimization. The end-tag is required.",
'-O' => "The start-tag is required for this element. The end-tag is optional, if your SGML declaration allows minimization."
);
$html .= "\n";
$html .= "getAttribute('name');
$html .= "\n";
} else {
$html .= "\n";
}
}
$html .= "
\n";
}
}
return $html;
}
sub formatElementDescription {
my $count = shift;
my $name = $elements[$count];
my $element = $elements{$name};
my $desc = &elementDescription($count);
my $html = "";
return "" if !defined($desc);
$html .= "Description\n";
$html .= $desc;
$html .= "\n\n";
$html .= &formatParents($count) if $option{'parents'};
$html .= &formatChildren($count) if $option{'children'};
$html .= "\n\n";
return $html;
}
sub formatParents {
my $count = shift;
my $name = $elements[$count];
my $element = $elements{$name};
my $html = "";
if (exists $PARENTS{$name}) {
$html .= "Parents\n";
$html .= "These elements contain ";
$html .= $element->getAttribute('name') . ":\n";
$html .= "";
my $pname;
foreach $pname (sort { uc($a) cmp uc($b) } keys %{$PARENTS{$name}}) {
my $child = $elements{$pname};
$html .= "";
$html .= "";
$html .= "" . $child->getAttribute('name') . "";
$html .= "";
$html .= "\n";
}
$html .= ".\n";
$html .= "\n\n";
}
return $html;
}
sub formatChildren {
my $count = shift;
my $name = $elements[$count];
my $element = $elements{$name};
my $html = "";
my $mixed = $element->getAttribute('content-type') eq 'mixed';
my $declared = (!$mixed &&
$element->getAttribute('content-type') ne 'element');
return "" if $declared; # can't be any children...
if (exists $CHILDREN{$name}
|| exists $POSSINCL{$name}
|| exists $POSSEXCL{$name}) {
$html .= "Children\n";
}
if (exists $CHILDREN{$name}) {
$html .= "The following elements occur in ";
$html .= $element->getAttribute('name') . ":\n";
$html .= "";
my $cname;
foreach $cname (sort { uc($a) cmp uc($b) } keys %{$CHILDREN{$name}}) {
my $child = $elements{$cname};
die "Unexpected error (1): can't find element \"$cname\".\n"
if !$child;
$html .= "";
$html .= "";
$html .= "";
$html .= $child->getAttribute('name');
$html .= "";
$html .= "";
$html .= "\n";
}
$html .= ".\n";
}
if (exists $POSSINCL{$name}) {
$html .= "In some contexts, the following elements are\n";
$html .= "allowed anywhere:\n";
$html .= "\n";
my $cname;
foreach $cname (sort { uc($a) cmp uc($b) } keys %{$POSSINCL{$name}}) {
my $child = $elements{$cname};
die "Unexpected error (2): can't find element \"$cname\".\n"
if !$child;
$html .= "";
$html .= "";
$html .= "";
$html .= $child->getAttribute('name');
$html .= "";
$html .= "";
$html .= "\n";
}
$html .= ".\n\n";
}
if (exists $POSSEXCL{$name}) {
$html .= "In some contexts, the following elements are\n";
$html .= "excluded:\n";
$html .= "\n";
my $cname;
foreach $cname (sort { uc($a) cmp uc($b) } keys %{$POSSEXCL{$name}}) {
my $element = $elements{$cname};
$html .= "";
$html .= "";
$html .= "";
$html .= $element->getAttribute('name');
$html .= "";
$html .= "";
$html .= "\n";
}
$html .= ".\n\n";
}
if (exists $CHILDREN{$name}
|| exists $POSSINCL{$name}
|| exists $POSSEXCL{$name}) {
$html .= "\n\n";
}
return $html;
}
sub formatElementExamples {
my $count = shift;
my $name = $elements[$count];
my $element = $elements{$name};
return "";
}
sub formatElementFooter {
my $count = shift;
my $html = "";
$html .= "
\n";
return $html;
}
# ----------------------------------------------------------------------
my $state = 'NONE';
my $depth = 0;
my $col = 0;
sub formatContentModel {
my $count = shift;
my $cm = shift;
my $node = $cm->getFirstChild();
my $html = "";
$state = "NONE";
$depth = 0;
$col = 0;
while ($node) {
if ($node->getNodeType == XML::DOM::ELEMENT_NODE) {
$html .= formatContentModelElement($node);
}
$node = $node->getNextSibling();
}
return $html;
}
sub formatContentModelElement {
my $node = shift;
my $html = "";
if ($node->getNodeType == XML::DOM::ELEMENT_NODE) {
if ($node->getTagName() eq 'sequence-group') {
$html .= &formatCMGroup($node, ",");
} elsif ($node->getTagName() eq 'or-group') {
$html .= &formatCMGroup($node, "|");
} elsif ($node->getTagName() eq 'and-group') {
$html .= &formatCMGroup($node, "&");
} elsif ($node->getTagName() eq 'element-name') {
$html .= &formatCMElement($node);
} elsif ($node->getTagName() eq 'parament-name') {
$html .= &formatCMParament($node);
} elsif ($node->getTagName() eq 'pcdata') {
$html .= &formatCMPCDATA($node);
} elsif ($node->getTagName() eq 'cdata') {
$html .= &formatCMCDATA($node);
} elsif ($node->getTagName() eq 'rcdata') {
$html .= &formatCMRCDATA($node);
} elsif ($node->getTagName() eq 'empty') {
$html .= &formatCMEMPTY($node);
} elsif ($node->getTagName() eq 'any') {
$html .= &formatCMANY($node);
} else {
die "Unexpected node: \"" . $node->getTagName() . "\"\n";
}
$node = $node->getNextSibling();
} else {
die "Unexpected node type.\n";
}
return $html;
}
sub formatCMGroup {
my $group = shift;
my $occur = $group->getAttribute('occurrence');
my $sep = shift;
my $first = 1;
my $html = "";
if ($state ne 'NONE' && $state ne 'OPEN') {
$html .= "\n";
$html .= " " x $depth if $depth > 0;
$col = $depth;
$state = 'NEWLINE';
}
$html .= "(";
$state = 'OPEN';
$depth++;
$col++;
my $node = $group->getFirstChild();
while ($node) {
if ($node->getNodeType == XML::DOM::ELEMENT_NODE) {
if (!$first) {
$html .= $sep;
$col++;
if ($state ne 'NEWLINE' && ($col > 60)) {
$html .= "\n";
$html .= " " x $depth if $depth > 0;
$col = $depth;
$state = 'NEWLINE';
}
}
$html .= &formatContentModelElement($node);
$first = 0;
}
$node = $node->getNextSibling();
}
$html .= ")";
$col++;
if ($occur) {
$html .= $occur;
$col++;
}
$state = 'CLOSE';
$depth--;
return $html;
}
sub formatCMElement {
my $element = shift;
my $name = $element->getAttribute('name');
my $occur = $element->getAttribute('occurrence');
my $href = "";
my $html = "";
$name = lc($name) if !$option{'case-sensitive'};
if ($state eq 'CLOSE') {
$html .= "\n";
$html .= " " x $depth if $depth > 0;
$col = $depth;
$state = 'NEWLINE';
}
$html .= "";
$html .= $element->getAttribute('name');
$html .= "";
$col += length($name);
if ($occur) {
$html .= $occur;
$col++;
}
$state = 'ELEMENT';
return $html;
}
sub formatCMParament {
my $element = shift;
my $name = $element->getAttribute('name');
my $html = "";
if ($state eq 'CLOSE') {
$html .= "\n";
$html .= " " x $depth if $depth > 0;
$col = $depth;
$state = 'NEWLINE';
}
$html .= "";
$html .= "\%" . $name . ";";
$html .= "";
$col += length($name) + 2;
$state = 'PARAMENT';
return $html;
}
sub formatCMPCDATA {
my $html = "";
$html .= "#PCDATA";
$col += 7;
$state = 'PCDATA';
return $html;
}
sub formatCMCDATA {
my $html = "";
$html .= "CDATA";
$col += 5;
$state = 'CDATA';
return $html;
}
sub formatCMRCDATA {
my $html = "";
$html .= "RCDATA";
$col += 5;
$state = 'RCDATA';
return $html;
}
sub formatCMEMPTY {
my $html = "";
$html .= "EMPTY";
$col += 5;
$state = 'EMPTY';
return $html;
}
sub formatCMANY {
my $html = "";
$html .= "ANY";
$col += 3;
$state = 'ANY';
return $html;
}
# ======================================================================
sub formatEntity {
my $count = shift;
my $name = $entities[$count];
my $entity = $entities{$name};
my $html = "";
my $textnl;
if ($expanded eq 'expanded') {
$textnl = $entity->getElementsByTagName("text-expanded");
} else {
$textnl = $entity->getElementsByTagName("text");
}
$html .= &formatEntityHeader($count);
$html .= &formatEntityTitle($count);
$html .= &formatEntitySynopsis($count, $textnl)
if $option{'synopsis'};
$html .= &formatEntityAppearsIn($count) if $option{'appears-in'};
$html .= &formatEntityDescription($count) if $option{'description'};
$html .= &formatEntityExamples($count) if $option{'examples'};
$html .= &formatEntityFooter($count);
return $html;
}
sub formatEntityHeader {
my $count = shift;
my $html = "";
my $name = $entities[$count];
$html .= "\n";
$html .= "\n";
$html .= "\n\n";
return $html;
}
sub formatEntityTitle {
my $count = shift;
my $name = $entities[$count];
my $entity = $entities{$name};
my $type = $entity->getAttribute("type");
my $html = "";
$html .= "\n";
$html .= "";
$html .= $entity->getAttribute('name');
$html .= "\n";
if ($type eq 'gen') {
$html .= "General Entity\n";
} elsif ($type eq 'ndata'
|| $type eq 'cdata'
|| $type eq 'sdata'
|| $type eq 'pi') {
$html .= "" . uc($type) . " Entity\n";
} else {
$html .= "Parameter Entity\n";
}
$html .= "\n\n";
$html .= "\n";
$html .= "" . $entity->getAttribute('name') . "\n";
$html .= "";
$html .= &entityRefpurpose($count);
$html .= "\n";
$html .= "\n\n";
}
sub formatEntitySynopsis {
my $count = shift;
my $textnl = shift;
my $name = $entities[$count];
my $entity = $entities{$name};
my $html = "";
my $type = $entity->getAttribute("type");
my $public = entify($entity->getAttribute("public"));
my $system = entify($entity->getAttribute("system"));
my $text = "";
if ($textnl->getLength() > 0) {
my $textnode = $textnl->item(0);
my $content = $textnode->getFirstChild();
if ($content) {
$text = $content->getData();
} else {
$text = "";
}
}
$html .= "\n";
$html .= "\n";
$html .= "\n";
$html .= "\n";
$html .= "\n";
$html .= "\n";
$html .= "\n";
$html .= "\n";
$html .= "$match";
} else {
$html .= $match;
}
} else {
$html .= $match;
}
}
$html .= $text;
$html .= "\n";
$html .= "
\n";
}
}
if ($type eq 'ndata' || $type eq 'cdata') {
my $notation = $entity->getAttribute('notation');
$html .= uc($type) . " Entity";
$html .= "\n";
$html .= "\n";
$html .= "\n";
$html .= "getAttribute('name') . ":\n";
$html .= "\n";
for (my $count = 0; $count <= $#ents; $count++) {
my $entity = $entities{$ents[$count]};
$html .= "";
$html .= "getAttribute('type') . ".";
$html .= $entity->getAttribute('name') . "\">";
$html .= $entity->getAttribute('name');
$html .= "";
$html .= "\n";
}
$html .= "\n";
$html .= "\n";
}
return $html;
}
sub formatEntityDescription {
my $count = shift;
my $name = $entities[$count];
my $entity = $entities{$name};
my $desc = &entityDescription($count);
my $html = "";
return "" if !defined($desc);
$html .= "Description\n";
$html .= $desc;
$html .= "\n\n";
return $html;
}
sub formatEntityExamples {
my $count = shift;
my $name = $entities[$count];
my $entity = $entities{$name};
return "";
}
sub formatEntityFooter {
my $count = shift;
my $html = "";
$html .= "\n";
return $html;
}
# ======================================================================
sub formatNotation {
my $count = shift;
my $html = "";
my $name = $notations[$count];
my $element = $notations{$name};
$html .= &formatNotationHeader($count);
$html .= &formatNotationTitle($count);
if ($option{'synopsis'}) {
$html .= &formatNotationSynopsis($count);
}
$html .= &formatNotationDescription($count)
if $option{'description'};
$html .= &formatNotationExamples($count) if $option{'examples'};
$html .= &formatNotationFooter($count);
}
sub formatNotationHeader {
my $count = shift;
my $html = "";
my $name = $notations[$count];
$html .= "\n";
$html .= "\n";
$html .= "\n\n";
return $html;
}
sub formatNotationTitle {
my $count = shift;
my $name = $notations[$count];
my $notation = $notations{$name};
my $html = "";
$html .= "\n";
$html .= "";
$html .= $notation->getAttribute('name');
$html .= "\n";
$html .= "Notation\n";
$html .= "\n\n";
$html .= "\n";
$html .= "" . $notation->getAttribute('name') . "\n";
$html .= "";
$html .= ¬ationRefpurpose($count);
$html .= "\n";
$html .= "\n\n";
}
sub formatNotationSynopsis {
my $count = shift;
my $name = $notations[$count];
my $notation = $notations{$name};
my $html = "";
my $public = entify($notation->getAttribute("public"));
my $system = entify($notation->getAttribute("system"));
$html .= "\n";
if ($public) {
$html .= "\nPublic identifier:\n";
$html .= "$public.";
$html .= "\n\n";
}
if ($system) {
$html .= "\nSystem identifier:\n";
$html .= "$system.";
$html .= "\n\n";
}
if (!$public && !$system) {
$html .= "\nSystem
specified\n";
$html .= "without a system identifier.";
$html .= "\n\n";
}
return $html;
}
sub formatNotationDescription {
my $count = shift;
my $name = $notations[$count];
my $notation = $notations{$name};
my $desc = ¬ationDescription($count);
my $html = "";
return "" if !defined($desc);
$html .= "Description\n";
$html .= $desc;
$html .= "\n\n";
return $html;
}
sub formatNotationExamples {
my $count = shift;
my $name = $notations[$count];
my $element = $notations{$name};
return "";
}
sub formatNotationFooter {
my $count = shift;
my $html = "";
$html .= "\n";
return $html;
}
# ======================================================================
sub writeElementIndexes {
my $basedir = shift;
my $title = entify($dtd->getDocumentElement->getAttribute('title'));
my ($entfile, $sgmfile, $sysdir);
local (*F, $_);
$entfile = $basedir . "/" . $config{$expanded . "-element-index"} . ".ent";
$sgmfile = $basedir . "/" . $config{$expanded . "-element-index"} . $fileext;
$sysdir = $config{$expanded . "-element-dir"};
open (F, ">$entfile");
foreach $name (@elements) {
my $basename = $ELEMBASE{$name};
print F "\n";
print F "\n";
}
close (F);
open (F, ">$sgmfile");
print F "$title Element Reference\n";
foreach $name (@elements) {
print F "&$baseid.elem.$name;\n";
}
print F "\n";
close (F);
}
sub writeEntityIndexes {
my $basedir = shift;
my $title = entify($dtd->getDocumentElement->getAttribute('title'));
my ($entfile, $sgmfile, $sysdir);
local (*F, $_);
$entfile = $basedir . "/" . $config{$expanded . "-entity-index"} . ".ent";
$sgmfile = $basedir . "/" . $config{$expanded . "-entity-index"} . $fileext;
$sysdir = $config{$expanded . "-entity-dir"};
open (F, ">$entfile");
foreach $name (@entities) {
my $entity = $entities{$name};
my $basename = $ENTBASE{$name};
print F "\n";
print F "getAttribute('type'), ".$name \"purpose\">\n";
}
close (F);
open (F, ">$sgmfile");
print F "$title Entity Reference\n";
foreach $name (@entities) {
print F "&$baseid.param.$name;\n";
}
print F "\n";
close (F);
}
sub writeNotationIndexes {
my $basedir = shift;
my $title = entify($dtd->getDocumentElement->getAttribute('title'));
my ($notnfile, $sgmfile, $sysdir);
local (*F, $_);
$notnfile = $basedir . "/" . $config{"notation-index"} . ".ent";
$sgmfile = $basedir . "/" . $config{"notation-index"} . $fileext;
$sysdir = $config{"notation-dir"};
open (F, ">$notnfile");
foreach $name (@notations) {
my $notation = $notations{$name};
my $basename = $NOTBASE{$name};
print F "\n";
print F "\n";
}
close (F);
open (F, ">$sgmfile");
print F "$title Notation Reference\n";
foreach $name (@notations) {
print F "&$baseid.notn.$name;\n";
}
print F "\n";
close (F);
}
sub writeIndex {
my $basedir = shift;
my $title = entify($dtd->getDocumentElement->getAttribute('title'));
my $entfile = $config{"expanded-entity-index"};
my $elemfile = $config{"expanded-element-index"};
my $notfile = $config{"notation-index"};
my $root = $dtd->getDocumentElement();
my $elements = $root->getElementsByTagName('element');
my $entities = $root->getElementsByTagName('entity');
my $notations = $root->getElementsByTagName('notation');
my $elemcount = $elements->getLength();
my $entcount = $entities->getLength();
my $notcount = $notations->getLength();
local (*F, $_);
# nop;
}
1;