package XML::Handler::Dtd2DocBook; use base qw(XML::Handler::Dtd2Html); use vars qw($VERSION); $VERSION="0.41"; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = { doc => new XML::Handler::Dtd2DocBook::Document(), comments => [] }; bless($self, $class); return $self; } ############################################################################### package XML::Handler::Dtd2DocBook::Document; use HTML::Template; use File::Basename; use base qw(XML::Handler::Dtd2Html::DocumentBook); sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = $class->SUPER::new(); $self->{hlink} = 0; $self->{preformatted} = "programlisting"; $self->{emphasis} = "emphasis"; $self->{width} = 65; bless($self, $class); return $self; } sub _process_args { my $self = shift; my %hash = @_; $self->SUPER::_process_args(@_); $self->{generator} = "dtd2db " . $XML::Handler::Dtd2DocBook::VERSION . " (Perl " . $] . ")"; if (defined $hash{path_tmpl}) { $self->{path_tmpl} = [ $hash{path_tmpl} ]; } else { my $language = $hash{language} || 'en'; my $path = $INC{'XML/Handler/Dtd2DocBook.pm'}; $path =~ s/\.pm$//i; $self->{path_tmpl} = [ $path . '/' . $language, $path ]; } } sub _mk_text_anchor { my $self = shift; my($type, $name) = @_; my $linkend = $type . "." . $name; return "" . $name . ""; } sub _mk_index_anchor { my $self = shift; my($type, $name) = @_; return $name; } sub _mk_outfile { my $self = shift; my($type, $name) = @_; my $uri_name = $name; $uri_name =~ s/[ :]/_/g; $uri_name = $self->_mk_filename($uri_name); return $self->{outfile} . "." . $type . "." . $uri_name . ".gen"; } sub _mk_system { my $self = shift; my($type, $name) = @_; my $uri_name = $name; $uri_name =~ s/[ :]/_/g; $uri_name = $self->_mk_filename($uri_name); return $self->{basename} . "." . $type . "." . $uri_name . ".gen"; } sub _get_doc_attrs { my $self = shift; my ($name) = @_; my @doc_attrs = (); my @attrs = (); if (exists $self->{hash_attr}->{$name}) { foreach my $attr (@{$self->{hash_attr}->{$name}}) { my @doc = (); my @tag = (); if ($self->{flag_comment} and exists $attr->{comments}) { foreach my $comment (@{$attr->{comments}}) { my ($doc, $r_tags) = $self->_extract_doc($comment); if (defined $doc) { my $data = $self->_process_text($doc, $name); push @doc, { data => $data }; } foreach (@{$r_tags}) { my ($href, $entry, $data) = @{$_}; unless ( uc($entry) eq "BRIEF" or uc($entry) eq "HIDDEN" ) { if ($entry =~ /^SAMPLE($|\s)/i) { $entry =~ s/^SAMPLE\s*//i; $data = "<$self->{preformatted}>" . $self->_mk_example($data) . "{preformatted}>"; push @tag, { entry => $entry, data => $data, }; } else { $data = $self->_process_text($data, $name, $href); push @tag, { entry => $entry, data => $data, }; } } } } } push @doc_attrs, { name_ent => "elt." . $name . "." . $attr->{aName}, name => $attr->{aName}, doc => [ @doc ], tag => [ @tag ], }; push @attrs, { name_ent => "elt." . $name . "." . $attr->{aName}, }; } } return (\@doc_attrs, \@attrs); } sub _mk_tree { my $self = shift; my ($name, $depth) = @_; return if ($self->{hash_element}->{$name}->{done}); $self->{hash_element}->{$name}->{done} = 1; die __PACKAGE__,"_mk_tree: INTERNAL ERROR ($name).\n" unless (defined $self->{hash_element}->{$name}->{uses}); return unless (scalar keys %{$self->{hash_element}->{$name}->{uses}}); my %done = (); $self->{_tree_depth} = $depth if ($depth > $self->{_tree_depth}); $self->{_tree} .= "\n"; foreach (keys %{$self->{hash_element}->{$name}->{uses}}) { next if ($_ eq $name); next if (exists $done{$_}); $done{$_} = 1; $self->{_tree} .= " " . $self->_mk_text_anchor("elt", $_) . "\n"; $self->_mk_tree($_, $depth+1); $self->{_tree} .= " \n"; } $self->{_tree} .= "\n"; } sub generateTree { my $self = shift; $self->{_tree_depth} = 1; $self->{_tree} = "\n"; $self->{_tree} .= " " . $self->_mk_text_anchor("elt", $self->{root_name}) . "\n"; if (exists $self->{hash_element}->{$self->{root_name}}) { $self->_mk_tree($self->{root_name}, $self->{_tree_depth}); } else { warn "$self->{root_name} declared in DOCTYPE is an unknown element.\n"; } $self->{_tree} .= " \n"; $self->{_tree} .= "\n"; $self->{_tree} = "" if ($self->{_tree_depth} > 7); $self->{template}->param( tree => $self->{_tree}, ); delete $self->{_tree}; } sub generateEntity { my $self = shift; my ($prefix, $r_list) = @_; my @ent = (); foreach (@{$r_list}) { push @ent, { name => "&${prefix}.$_;", }; } $self->{template}->param( ent => \@ent, ); } sub GenerateDocBook { my $self = shift; warn "No element declaration captured.\n" unless (scalar keys %{$self->{hash_element}}); $self->_process_args(@_); $self->_test_sensitive(); my @elements = sort keys %{$self->{hash_element}}; my @entities = sort keys %{$self->{hash_entity}}; my @notations = sort keys %{$self->{hash_notation}}; my @examples = @{$self->{examples}}; my $template = "book.tmpl"; $self->{template} = new HTML::Template( filename => $template, path => $self->{path_tmpl}, ); die "can't create template with $template ($!).\n" unless (defined $self->{template}); $self->{template}->param( generator => $self->{generator}, date => $self->{now}, ); $self->{template}->param( name => $self->{basename}, title => $self->{title}, nb_elt => scalar @elements, nb_ent => scalar @entities, nb_not => scalar @notations, nb_ex => scalar @examples, ); my $filename = $self->{outfile} . ".xml"; open OUT, "> $filename" or die "can't open $filename ($!)\n"; print OUT $self->{template}->output(); close OUT; $template = "prolog.tmpl"; $self->{template} = new HTML::Template( filename => $template, path => $self->{path_tmpl}, ); die "can't create template with $template ($!).\n" unless (defined $self->{template}); $self->{template}->param( generator => $self->{generator}, date => $self->{now}, ); $self->{template}->param( name => $self->{dtd}->{Name}, publicId => $self->{dtd}->{PublicId}, systemId => $self->{dtd}->{SystemId}, ); $filename = $self->{outfile} . ".prolog.gen"; open OUT, "> $filename" or die "can't open $filename ($!)\n"; print OUT $self->{template}->output(); close OUT; if (scalar @elements) { $template = "index.tmpl"; $self->{template} = new HTML::Template( filename => $template, path => $self->{path_tmpl}, ); die "can't create template with $template ($!).\n" unless (defined $self->{template}); $self->{template}->param( generator => $self->{generator}, date => $self->{now}, ); $self->{template}->param( idx_elt => 1, idx_ent => 0, idx_not => 0, lst_ex => 0, ); $self->generateEntity("elt", \@elements); $self->generateTree(); $filename = $self->{outfile} . ".elements.gen"; open OUT, "> $filename" or die "can't open $filename ($!)\n"; print OUT $self->{template}->output(); close OUT; $template = "element.tmpl"; $self->{template} = new HTML::Template( filename => $template, path => $self->{path_tmpl}, loop_context_vars => 1, ); die "can't create template with $template ($!).\n" unless (defined $self->{template}); $self->{template}->param( generator => $self->{generator}, date => $self->{now}, ); $filename = $self->{outfile} . ".elements.ent"; open ENT, "> $filename" or die "can't open $filename ($!)\n"; foreach my $name (@elements) { my $decl = $self->{hash_element}->{$name}; my $model = $decl->{Model}; $self->{template}->param( name => $name, fname => $self->_mk_filename($name), f_model => $self->_format_content_model($model), attrs => $self->_get_attributes($name), parents => $self->_get_parents($decl), childs => $self->_get_childs($decl), is_mixed => ($model =~ /#PCDATA/) ? 1 : 0, is_element => ($model !~ /(ANY|EMPTY)/) ? 1 : 0, ); $filename = $self->_mk_outfile("elt", $name); open OUT, "> $filename" or die "can't open $filename ($!)\n"; print OUT $self->{template}->output(); close OUT; my $sys = $self->_mk_system("elt", $name); print ENT "\n"; } close ENT; } if (scalar @entities) { $template = "index.tmpl"; $self->{template} = new HTML::Template( filename => $template, path => $self->{path_tmpl}, ); die "can't create template with $template ($!).\n" unless (defined $self->{template}); $self->{template}->param( generator => $self->{generator}, date => $self->{now}, ); $self->{template}->param( idx_elt => 0, idx_ent => 1, idx_not => 0, lst_ex => 0, ); $self->generateEntity("ent", \@entities); $filename = $self->{outfile} . ".entities.gen"; open OUT, "> $filename" or die "can't open $filename ($!)\n"; print OUT $self->{template}->output(); close OUT; $template = "entity.tmpl"; $self->{template} = new HTML::Template( filename => $template, path => $self->{path_tmpl}, ); die "can't create template with $template ($!).\n" unless (defined $self->{template}); $self->{template}->param( generator => $self->{generator}, date => $self->{now}, ); $filename = $self->{outfile} . ".entities.ent"; open ENT, "> $filename" or die "can't open $filename ($!)\n"; foreach my $name (@entities) { my $decl = $self->{hash_entity}->{$name}; $self->{template}->param( name => $name, fname => $self->_mk_filename($name), value => (exists $decl->{Value}) ? ord($decl->{Value}) : undef, publicId => $decl->{PublicId}, systemId => $decl->{SystemId}, ); $filename = $self->_mk_outfile("ent", $name); open OUT, "> $filename" or die "can't open $filename ($!)\n"; print OUT $self->{template}->output(); close OUT; my $sys = $self->_mk_system("ent", $name); print ENT "\n"; } close ENT; } if (scalar @notations) { $template = "index.tmpl"; $self->{template} = new HTML::Template( filename => $template, path => $self->{path_tmpl}, ); die "can't create template with $template ($!).\n" unless (defined $self->{template}); $self->{template}->param( generator => $self->{generator}, date => $self->{now}, ); $self->{template}->param( idx_elt => 0, idx_ent => 0, idx_not => 1, lst_ex => 0, ); $self->generateEntity("not", \@notations); $filename = $self->{outfile} . ".notations.gen"; open OUT, "> $filename" or die "can't open $filename ($!)\n"; print OUT $self->{template}->output(); close OUT; $template = "notation.tmpl"; $self->{template} = new HTML::Template( filename => $template, path => $self->{path_tmpl}, ); die "can't create template with $template ($!).\n" unless (defined $self->{template}); $self->{template}->param( generator => $self->{generator}, date => $self->{now}, ); $filename = $self->{outfile} . ".notations.ent"; open ENT, "> $filename" or die "can't open $filename ($!)\n"; foreach my $name (@notations) { my $decl = $self->{hash_notation}->{$name}; $self->{template}->param( name => $name, fname => $self->_mk_filename($name), publicId => $decl->{PublicId}, systemId => $decl->{SystemId}, ); $filename = $self->_mk_outfile("not", $name); open OUT, "> $filename" or die "can't open $filename ($!)\n"; print OUT $self->{template}->output(); close OUT; my $sys = $self->_mk_system("not", $name); print ENT "\n"; } close ENT; } if (scalar @examples) { $template = "index.tmpl"; $self->{template} = new HTML::Template( filename => $template, path => $self->{path_tmpl}, ); die "can't create template with $template ($!).\n" unless (defined $self->{template}); $self->{template}->param( generator => $self->{generator}, date => $self->{now}, ); $self->{template}->param( idx_elt => 0, idx_ent => 0, idx_not => 0, lst_ex => 1, ); $self->generateEntity("ex", \@examples); $filename = $self->{outfile} . ".examples.gen"; open OUT, "> $filename" or die "can't open $filename ($!)\n"; print OUT $self->{template}->output(); close OUT; $template = "example.tmpl"; $self->{template} = new HTML::Template( filename => $template, path => $self->{path_tmpl}, ); die "can't create template with $template ($!).\n" unless (defined $self->{template}); $self->{template}->param( generator => $self->{generator}, date => $self->{now}, ); $filename = $self->{outfile} . ".examples.ent"; open ENT, "> $filename" or die "can't open $filename ($!)\n"; foreach my $example (@examples) { $self->{template}->param( name => $example, fname => $self->_mk_filename($example), page_title => "Example " . $example, example => $self->_mk_example($example), ); $filename = $self->_mk_outfile("ex", $example); open OUT, "> $filename" or die "can't open $filename ($!)\n"; print OUT $self->{template}->output(); close OUT; my $sys = $self->_mk_system("ex", $example); print ENT "\n"; } close ENT; } $filename = $self->{outfile} . ".customs.ent"; unless ( -e $filename) { $template = "custom.tmpl"; $self->{template} = new HTML::Template( filename => $template, path => $self->{path_tmpl}, ); die "can't create template with $template ($!).\n" unless (defined $self->{template}); my @ent = (); my ($r_doc, $r_tag) = $self->_get_doc($self->{dtd}); push @ent, { name => "prolog." . $self->{dtd}->{Name}, brief => $self->_get_brief($self->{dtd}), doc => $r_doc, tag => $r_tag, }; foreach my $name (@elements) { my $decl = $self->{hash_element}->{$name}; ($r_doc, $r_tag) = $self->_get_doc($decl); my ($r_doc_attrs, $r_attrs) = $self->_get_doc_attrs($name); push @ent, { name => "elt." . $name, brief => $self->_get_brief($decl), doc => $r_doc, tag => $r_tag, attrs => $r_attrs, doc_attrs => $r_doc_attrs, }; } foreach my $name (@entities) { my $decl = $self->{hash_entity}->{$name}; ($r_doc, $r_tag) = $self->_get_doc($decl); push @ent, { name => "ent." . $name, brief => $self->_get_brief($decl), doc => $r_doc, tag => $r_tag, }; } foreach my $name (@notations) { my $decl = $self->{hash_notation}->{$name}; ($r_doc, $r_tag) = $self->_get_doc($decl); push @ent, { name => "not." . $name, brief => $self->_get_brief($decl), doc => $r_doc, tag => $r_tag, }; } $self->{template}->param( ent => \@ent, ); open OUT, "> $filename" or die "can't open $filename ($!)\n"; print OUT $self->{template}->output(); close OUT; } } 1; __END__ =head1 NAME XML::Handler::Dtd2DocBook - SAX2 handler for generate a DocBook documentation from a DTD =head1 SYNOPSIS use XML::SAX::Expat; use XML::Handler::Dtd2DocBook; $handler = new XML::Handler::Dtd2DocBook; $parser = new XML::SAX::Expat(Handler => $handler); $parser->set_feature("http://xml.org/sax/features/external-general-entities", 1); $doc = $parser->parse( [OPTIONS] ); $doc->GenerateDocBook( [PARAMS] ); =head1 DESCRIPTION All comments before a declaration are captured. All entity references inside attribute values are expanded. =head1 AUTHOR Francois Perrad, francois.perrad@gadz.org =head1 SEE ALSO dtd2db.pl =head1 COPYRIGHT (c) 2003 Francois PERRAD, France. All rights reserved. This program is distributed under the Artistic License. =cut