Takaisin DigPubin kotisivulle LIITE 4. Muunnosohjelmakoodit

Seuraava Edellinen Alkuun
Seuraava Edellinen Alkuun


  • LIITE 4. Muunnosohjelmakoodit

  • 1 Sgmlspl-ohjelmakoodi Docbook.dtd:n mukaisen SGML-tekstin muuntamiseksi LaTeX-muotoon
  • 2 Sgmlspl-ohjelmakoodi Docbook.dtd:n mukaisen SGML-tekstin muuntaminen HTML-muotoon


    LIITE 4. Muunnosohjelmakoodit

    1 Sgmlspl-ohjelmakoodi Docbook.dtd:n mukaisen SGML-tekstin muuntamiseksi LaTeX-muotoon

    ########################################################################
    # SGMLSpm-ohjelmakoodi, joka muuntaa SGML-dokumentin LaTeX-muotoon.
    # Tama ohjelmakoodi on tehty erityisesti Docbook.dtd-muotoisen pro gradu
    # -tutkielmatekstin muunnosta varten, eika siis kata kaikkia Docbook.dtd:n
    # ominaisuuksia.
    # Tama ohjelma kayttaa SGMLS.pm-luokkakirjastoa, joka osaa kasitella
    # SGMLS- ja NSGMLS-jasentajien tuottamaa tietoa. 
    ########################################################################
    
    # Otetaan kayttoon SGMLS-paketti.
    use SGMLS;		
    # Otetaan kayttoon tulostuspino, jota sgmlspl kayttaa.
    use Output;		
    
    #
    # Dokumentin kasittely.
    #
    sgml('start', sub {});
    sgml('end', sub {});
    
    # Nimien lkm-muuttuja, jotta ne saadaan muotoiltua oikein.
    $Nimien_lkm = 0;
    # Onko otsikkosivu jo tulostettu.
    $Otsikon_tulostus = 0;      
    # Apumuuttuja sivunumeron alustusta varten.
    $Johdantosivu = 0;        
    # Muuttujia, joihin tallennetaan nimet myohempaa kasittelya varten.
    $Etunimi1 = '';
    $Etunimi2 = '';
    $Etunimi3 = '';
    $Sukunimi1 = '';
    $Sukunimi2 = '';
    $Sukunimi3 = '';
    # Taulukon leveydeksi asetettu 14 cm.
    $tab_width = 14;
    # Kuvien oletuskoot.
    $fig_height = "10cm";
    $fig_width = "13cm";
    $Collabname = '';
    $Corpauthor1 = '';
    $Corpauthor2 = '';
    $Corpauthor3 = '';
    
    #
    # Elementtien kasittely.
    #
    
    # Element: ARTICLE, joka aloittaa dokumentin.
    sgml('<ARTICLE>', "\\documentstyle[12pt,html]{artikkeli}\n" .
    # Latexonly-maarittelyt tarvitaan latex2html-ohjelmaa varten.
    #   "\\begin{latexonly}\n" .
       "\\language\\finnish\n" .
    #   "\\end{latexonly}\n" .
       "\\input{psfig}\n" .
       "\\tolerance=1500\n" .
       "\\setlength{\\parskip}{3ex}\n" );
    sgml('</ARTICLE>', "\\end{document}\n");
    
    # Element: ARTHEADER, muotoillaan etusivu.
    sgml('<ARTHEADER>', sub { push_output 'string'; } );
    sgml('</ARTHEADER>', sub {
        pop_output;
        output "\\title{$title}\n";
        output "\\pagestyle{empty}";
        output "\\author{$Etunimi1 $Sukunimi1 \\\\\n";
        output "    $Etunimi2 $Sukunimi2 \\\\\n";
        output "    $Etunimi3 $Sukunimi3 \\\\\n";
        output "\\\\\n";
        output "}\n";
        output "\\date{}\n";
        output "\\setlength{\\textwidth}{150mm}\n";
        output "\\setlength{\\textheight}{230mm}\n";
        output "\\setlength{\\topmargin}{0mm}\n";
        output "\\parindent=0mm\n";
        output "\\parskip\\bigskipamount\n";
        output "\\begin{document}\n\\maketitle\n";
        output "\\hspace{10cm}\\parbox{4cm}{$Collabname \\today}\n";
        output "\\vspace{5cm}\\begin{center}\n";
        output "$Corpauthor1 \\\\\n";
        output "$Corpauthor2 \\\\\n";
        output "$Corpauthor3 \\\\\n";
        output "\\end{center}\n";
        output "\\pagestyle{empty}";
        output "\\pagebreak\\tableofcontents\n";
    } );
    
    # Element: TITLE, tulostetaan otsikko vahan tapauskohtaisesti.
    sgml('<TITLE>', sub { push_output 'string'; });
    sgml('</TITLE>', sub {
        my $element = shift;
        my $data = pop_output;
        # Poistetaan otsikoista numerot, koska section tulostaa ne automaattisesti.
        @words = split(' ',$data,2);  
        if ($element->in(ARTHEADER)) 
        {
            $title = $data;
        }
        elsif ($element->in(SECT1)) { 
            # Lahdeluettelo tulostetaan sisallysluetteloon ilman numerointia.
            if ($data eq "LÄHDELUETTELO") 
            {
                output "\\section*{$data}\n"; 
                output "\\addcontentsline{toc}{section}{LÄHDELUETTELO}\n";
            } 
            # Ensimmainen luku aloittaa sivunumeroinnin.
            elsif ($words[0] == 1)
            {
                output "\\section{$words[1]}\n";
                output "\\pagestyle{myheadings}\n";
                output "\\setcounter{page}{1}\n";
                output "\\baselineskip=.7cm\n";
            }
            elsif ($Liite == 0) { output "\\section{$words[1]}\n"; }
            # Liitteen otsikkoa ei numeroida.
            else { 
                output "\\section*{$data}"; 
                output "\\addcontentsline{toc}{section}{$data}";
            }
        }
        elsif ($element->in(SECT2)) { 
            if ($Liite == 0) { output "\\subsection{$words[1]}\n"; }
            else { output "\\subsection*{$data}"; }
    
        }
        elsif ($element->in(SECT3)) { 
            if($Liite == 0) {
                output "\\subsubsection{$words[1]}\n"; 
            }
            else { output "\\subsubsection*{$data}"; }
        }
        elsif ($element->in(SECT4)) { output "\\paragraph*{$words[1] \\newline \\newline}\n"; }
        elsif ($element->in(ABSTRACT)) { output "\\paragraph*{$data \\newline \\newline}\n"; }
        elsif ($element->in(FIGURE))   { $title = $data; }
        elsif ($element->in(APPENDIX)) { $Liite++; }
        elsif ($element->in(TABLE)) { output "\\caption{$data}\n"; 
            output "\\label{$id}\n" if $id;
            output "\n";
        }
    });
    
    #Element: SUBTITLE
    sgml('<SUBTITLE>', sub { push_output 'string'; });
    sgml('</SUBTITLE>', sub { 
        my $element = shift;
        my $data = pop_output;
        # Yhdistetaan etusivun kaksi otsikkorivia yhteen muuttujaan 
        # rivinvaihdolla erotettuina.
        if ( $element->in(ARTHEADER))
        { 
            $title .= '\\\\'.$data;
           # $title .= $data;
        }
    });
    
    # Element: AUTHORGROUP
    sgml('<AUTHORGROUP>', "");
    sgml('</AUTHORGROUP>', sub { $Nimien_lkm = 0; });
    
    # Element: AUTHOR, tekijoiden nimet tulostetaan etusivulle allekkain ja
    # tiivistelmaan vierekkan.
    sgml('<AUTHOR>', sub { push_output 'string'; });
    sgml('</AUTHOR>', sub {
        my $element = shift;
        my $data = pop_output;
        if ( $Nimien_lkm == 1 ) { output "$Etunimi1 $Sukunimi1 \\\\\n"; }
        elsif ( $Nimien_lkm == 2 ) { output "$Etunimi2 $Sukunimi2 \\\\\n";}
        elsif ( $Nimien_lkm == 0 ) { output "$Etunimi3 $Sukunimi3 \\\\\n";}
    });
    
    # Element: FIRSTNAME, tallennetaan muuttujaan talteen.
    sgml('<FIRSTNAME>', sub { push_output('string'); });
    sgml('</FIRSTNAME>', sub { 
        if ( $Nimien_lkm == 0 ) { $Etunimi1 = pop_output; }
        elsif ( $Nimien_lkm == 1) { $Etunimi2 = pop_output; }
        elsif ( $Nimien_lkm == 2) { $Etunimi3 = pop_output; } 
    } );
    
    # Element: SURNAME, tallennetaan muuttujaan talteen.
    sgml('<SURNAME>', sub { push_output('string'); });
    sgml('</SURNAME>', sub { 
        if ( $Nimien_lkm == 0 ) { $Sukunimi1 = pop_output; $Nimien_lkm++; }
        elsif ( $Nimien_lkm == 1 ) { $Sukunimi2 = pop_output; $Nimien_lkm++;}
        elsif ( $Nimien_lkm == 2 ) { $Sukunimi3 = pop_output; $Nimien_lkm = 0; }
    } );
    
    # Element: ARTPAGENUMS
    sgml('<ARTPAGENUMS>', "");
    sgml('</ARTPAGENUMS>', "");
    
    # Element: COLLAB
    sgml('<COLLAB>', "");
    sgml('</COLLAB>', "");
    
    # Element: BEGINPAGE, tehdaan sivunvaihto.
    sgml('<BEGINPAGE>', "\\pagebreak\n");
    sgml('</BEGINPAGE>', "");
    
    # Element: ABSTRACT
    sgml('<ABSTRACT>', "" );
    sgml('</ABSTRACT>', sub { 
        # Rivinvalin asetus.
        output "\\baselineskip=.7cm\n";
        output "\\pagestyle{empty}";
    } );
    
    # Element: PARA
    sgml('<PARA>', "\n");
    sgml('</PARA>', "\n");
    
    # Element: CORPAUTHOR
    sgml('<CORPAUTHOR>', sub { push_output('string'); });
    sgml('</CORPAUTHOR>', sub { 
        if($Nimien_lkm == 0) { $Corpauthor1 = pop_output; $Nimien_lkm++; }
        elsif($Nimien_lkm == 1) { $Corpauthor2 = pop_output; $Nimien_lkm++; }
        elsif($Nimien_lkm == 2) { $Corpauthor3 = pop_output; $Nimien_lkm++; }
    });
    
    # Element: COLLABNAME
    sgml('<COLLABNAME>', sub { push_output('string');} );
    sgml('</COLLABNAME>', sub {
        $Collabname = pop_output;
    });
    
    # Element: OTHERCREDIT
    sgml('<OTHERCREDIT>', "");
    sgml('</OTHERCREDIT>', sub {
        output "$Etunimi1 $Sukunimi1 $honorific "; });
    
    # Element: HONORIFIC
    sgml('<HONORIFIC>', sub { push_output ('string'); });
    sgml('</HONORIFIC>', sub { $honorific = pop_output; });
    
    # Element: SECT1
    sgml('<SECT1>', "");
    sgml('</SECT1>', "");
    
    # Element: SECT2
    sgml('<SECT2>', "");
    sgml('</SECT2>', "");
    
    # Element: SECT3
    sgml('<SECT3>', "");
    sgml('</SECT3>', "");
    
    # Element: SECT4
    sgml('<SECT4>', "");
    sgml('</SECT4>', "");
    
    #Element: GRAPHIC, otetaan kuvatiedoston nimi muuttujaan.
    sgml('<GRAPHIC>', sub { 
        my $element = shift;
        $fileref = $element->attribute('FILEREF')->value;
        $fig_height = $element->attribute('LANG')->value;
        $fig_height = $fig_height . "cm";
    } );
    sgml('</GRAPHIC>', "");
    
    #Element: FIGURE, tehdaan kuvaviittaukset.
    sgml('<FIGURE>', "");
    sgml('</FIGURE>', sub {
        output "\\begin{figure}[htb]\n";
        # Tutkitaan, onko kuvalle maaritelty korkeus, muuten oletuksena on 10cm.
        if(!$fig_height) {
            output "\\centerline{\\psfig{figure=$fileref,height=10cm,width=$fig_width}}";
        }
        else {
            output "\\centerline{\\psfig{figure=$fileref,height=$fig_height,width=$fig_width}}";
        }
        if($title) { output "\\caption{$title}\n"; }
        output "\\end{figure}\n";
    });
    
    # Element: ITEMIZEDLIST, listan tulostus.
    sgml('<ITEMIZEDLIST>', "\\begin{itemize}" );
    sgml('</ITEMIZEDLIST>', "\\end{itemize}" );
    
    # Element: LISTITEM
    sgml('<LISTITEM>', sub { push_output(string); });
    sgml('</LISTITEM>', sub {
        my $member = pop_output;
        output "\\item\ $member";
    });
    
    #
    # Ohjelmalistat tulostetaan sisennettyna ja pienemmalla fontilla.
    # Verbatim-ymparisto mahdollistaa tekstin tulostamisen sellaisena kuin
    # se on tiedostoon tallennettu (mm. tyhjat tyhjina ja erikoismerkit oikein).
    #
    sgml('<PROGRAMLISTING>', "\n{\\footnotesize\\begin{verbatim}\n");
    sgml('</PROGRAMLISTING>', "\n\\endx{verbatim}}\n");
    
    #
    # TAULUKKOMAARITYKSET:
    #
    # Taulukko maaritellaan Latexin kelluvaan ymparistoon. Taulukko
    # tulostetaan pienemmalla fontilla tilan saastamiseksi. 
    #
    sgml('<TABLE>', sub {
      my $element = shift;
      $id = $element->attribute('ID')->value;
      # Taulkoissa fontin koko muutetaan mahdollisimman pieneksi (scriptsize).
      output "\n\\begin{table}[htbp]\n\\scriptsize\n";
    });
    sgml('</TABLE>', "\\end{table}\n");
    
    #
    # Tassa maaritellaan taulukon leveyden perusteella sarakkeiden
    # leveydet. Tab_width -muuttujan arvo jaetaan sarakkeiden
    # lukumaaralla, josta saadaan tasamittaisten sarakkeiden leveys.
    # Tama ratkaisu mahdollistaa parbox-muotoisten sarakkeiden kayton
    # taulukossa.
    #
    sgml('<TGROUP>', sub {
        my $element = shift;
        $table_columns = $element->attribute('COLS')->value;
        $col_sep = $element->attribute('COLSEP')->value;
        # Jos taulukossa on vain kaksi saraketta, ensimmaiselle sarakkeelle
        # varataan kuitenkin tilaa vain 1/3 taulukon leveydesta.
        if($table_columns == 2) { $width = $tab_width / 3; }
        else { $width = $tab_width / $table_columns; }
    });
    sgml('</TGROUP>', "");
    
    # Element: COLSPEC
    #
    # Tasta elementista luetaan sarakkeiden lukumaara, niiden tasaussuunta
    # seka viivoitusasetukset (col_sep=sarakkeiden ja row_sep=rivien valiset
    # viivat).
    sgml('<COLSPEC>', sub {
        my $element = shift;
        $align = $element->attribute('ALIGN')->value;
        if ($align=='left') { $align = 'l'; }
        elsif ($align=='right') { $align = 'r'; }
        elsif ($align=='center') { $align = 'c'; }
        $col_sep = $element->attribute('COLSEP')->value; 
        $row_sep = $element->attribute('ROWSEP')->value;
    });
    sgml('</COLSPEC>', "");
    
    #
    # Tasta aloitetaan tabular-ymparisto oletusasetusten mukaisen
    # tasauksen (align) mukaisesti.
    #
    sgml('<THEAD>', sub {
        output "\\vspace{2ex}\\begin{tabular}{$align" .
                "|$align" x ($table_columns - 1) . "}\n";
    });
    sgml('</THEAD>', "");
    
    #
    # Taulukon paataminen.
    #
    sgml('<TBODY>', "");
    sgml('</TBODY>', sub {
        # Tulostetaan alaviiva, ellei rivien valiviivoja ole muuten tulostettu.
        if ($row_sep==0) { output "\\\\ \\hline\n"; }
        output "\\end{tabular}\n";
    });
    
    #
    # Tulostetaan tuplaviiva otsikkorivin alle, muuten tulostetaan 
    # row_sep -muuttujan mukaisesti joko yksi viiva tai ei viivaa ollenkaan.
    #
    sgml('<ROW>', sub { $row = 0; });
    sgml('</ROW>', sub {
        my $element = shift;
        if ($element->in('THEAD')) {
    	output "\\\\ \\hline\\hline\n";
        } else {
            output "\\\\ \n";
            if ($row_sep) { output "\\hline\n"; }
        }
    });
    
    #
    # $row-muuttujan avulla tutkitaan, onko kyseessa ensimmaisen sarakkeen
    # arvo. Ellei nain ole, sarakkeen alkuun tulostetaan &, joka on Latexin
    # taulukkomaarityksia. Saraketeksti tulostetaan parbox-ymparistoon, jonka
    # ymparille lisataan viela vahan tyhjia.
    #
    sgml('<ENTRY>', sub {
        if ($row == 0) {
    	$row = 1;
            print "\\parbox[c]{" . $width . "cm}{\\raggedright\\vspace{2pt} ";
        } else {
    	print " & ";
            if($table_columns == 2 ) {
                print "\\parbox[c]{" . $width*2 . "cm}{\\raggedright\\vspace{2pt}";
            }
            else {
                print "\\parbox[c]{" . $width . "cm}{\\raggedright\\vspace{2pt} ";
            }
        }
    });
    sgml('</ENTRY>', "\\vspace{2pt}}\t");
    
    # Element: LINK
    sgml('<LINK>', "");
    sgml('</LINK>', "");
    
    # Element: ULINK
    # Viitaukset LaTeX2HTML-ohjelmalla tehtavaa HTML-muunnosta varten
    #
    sgml('<ULINK>', sub { push_output 'string'; });
    sgml('</ULINK>', sub {
        my $element = shift;
        my $data = pop_output;
        if ($data eq 'LaTeX') { $data = '{\\LaTeX}'; }
        $Address = $element->attribute('URL')->value;
        output "\\htmladdnormallink{$data}{$Address}";
    });
    
    # Element: FOOTNOTEREF
    sgml('<FOOTNOTEREF>', "");
    sgml('</FOOTNOTEREF>', "");
    
    # Element: FOOTNOTE
    # Tehdaan alaviittaus latexin footnote-ymparistolla.
    sgml('<FOOTNOTE>', "\\footnote{");
    sgml('</FOOTNOTE>', "}");
    
    # Element: QUOTE
    # Nama tulostetaan kursiivilla.
    sgml('<QUOTE>', "{\\em ");
    sgml('</QUOTE>', "\\/}");
    
    # Element: REFENTRY
    sgml('<REFENTRY>', "");
    sgml('</REFENTRY>', "");
    
    # Element: REFNAMEDIV
    sgml('<REFNAMEDIV>', "");
    sgml('</REFNAMEDIV>', "");
    
    # Element: REFNAME
    sgml('<REFNAME>', "\n");
    sgml('</REFNAME>', "\n");
    
    # Element: REFPURPOSE
    sgml('<REFPURPOSE>', "");
    sgml('</REFPURPOSE>', "");
    
    # Element: REFSECT1
    sgml('<REFSECT1>', "");
    sgml('</REFSECT1>', "");
    
    # Element: APPENDIX
    sgml('<APPENDIX>', "");
    sgml('</APPENDIX>', "");
    
    # Erikoismerkkien kasittely.
    sgml('|[LATEX]|', "{\\LaTeX}");
    sgml('|[LaTeX]|', "{\\LaTeX}");
    sgml('|[TeX]|', "{\\TeX}");
    sgml('|\"{a}|', "ä");
    sgml('|\"{A}|', "Ä");
    sgml('|\"{o}|', "ö");
    sgml('|\"{O}|', "Ö");
    sgml('|\"{e}|', "\\'{e}");
    sgml('|\%|', "\\%");
    sgml('|\_|', "\\_");
    sgml('|\~|', "\\~{}");
    sgml('|\^|', "\\^{}");
    sgml('|\&|', "\\&");
    sgml('|\\\\|', "\\");
    sgml('|\#|', "\\#");
    sgml('|\$|', "\\\$");
    sgml('|\§|', "\\S");
    
    #
    # &lt;, &gt;, ja &amp; muunnetaan <PROGRAMLISTING>-elementissa merkiksi,
    # muuten ne taytyy kasitella erikseen LaTeXissa.
    #
    sgml('|\<|', sub {
        my ($data,$event) = @_;
        if ($event->element->name eq 'PROGRAMLISTING') {
          output "\<";	
        } else {
          output "\$\<\$";	
        }
    });
    sgml('|\>|', sub {
        my ($data,$event) = @_;
        if ($event->element->name eq 'PROGRAMLISTING') {
          output "\>";	
        } else {
          output "\$\>\$";	
        }
    });
    sgml('|\&|', sub {
        my ($data,$event) = @_;
        if ($event->element->name eq 'PROGRAMLISTING') {
          output "\&";	
        } else {
          output "\\\&";	
        }
    });
    
    ########################################################################
    # CDATA-elementtien kasittely: merkit, jotka aiheuttavat LaTeXissa 
    # ongelmia.
    ########################################################################
    
    sgml('cdata',sub {
        my ($data,$event) = @_;
        unless ($event->element->name eq 'PROGRAMLISTING') {
    	$data =~ s/\\/\\verb\|\\\|/g; # backslash
    	$data =~ s/\{/\\\{/g;	# opening brace
    	$data =~ s/\}/\\\}/g;	# closing brace
    	$data =~ s/\#/\\\#/g;	# hash
    	$data =~ s/\$/\\\$/g;	# dollar
    	$data =~ s/\&/\\\&/g;	# ampersand
    	$data =~ s/\~/\\\~/g;	# tilde
    	$data =~ s/\^/\\\^/g;	# caret
        }
        output $data;
    });
    
    
    ########################################################################
    # CDATA-elementtien kasittely. Esim. liitetiedostot ovat ulkoisia
    # entiteetteja, jotka luetaan dokumenttiin.
    ########################################################################
    sgml('entity',sub {
        my $entity = shift;
        my $filename = $entity->filenames->[0] || $entity->sysid;
        if ($entity->type eq 'CDATA') {
    	if (-r $filename) {
    	    unless (open INPUT, "<$filename") {
    		die "Cannot open external file $filename\n";
    	    }
    	    while (<INPUT>) {
    		output $_;
    	    }
    	    close INPUT;
    	} else {
    	    die "Cannot read file $filename\n";
    	}
        } else {
    	die "Cannot handle external entity with type " . $entity->type . "\n";
        }
    });
    
    #
    # Virhetilanteiden kasittely.
    #
     sgml('start_element',sub { die "Unknown element: " . $_[0]->name; });
     sgml('sdata',sub { die "Unknown SDATA: " . $_[0]; });
     sgml('pi',sub { die "Unknown processing instruction: " . $_[0]; });
     sgml('start_subdoc',sub { die "Unknown subdoc entity: " . $_[0]->name; });
    
    1;
    
    

    2 Sgmlspl-ohjelmakoodi Docbook.dtd:n mukaisen SGML-tekstin muuntaminen HTML-muotoon

    #######################################################################
    # SGMLSPL-ohjelmakoodi, joka muuntaa Docbook.dtd:n mukaisen tiedoston
    # HTML-muotoon.
    # Tassa muunnoksessa on huomioitu vain ne docbook.dtd:n tekstitunnisteet,
    # joita on kaytetty tutkielmatekstissa.
    # Tama ohjelma kayttaa SGMLS.pm-luokkakirjastoa, joka kasittelee SGMLS-
    # ja NSGMLS-jasentimien tuottamia tietoja.   
    ########################################################################
    
    # Otetaan kayttoon SGMLS-paketti.
    use SGMLS;		
    # Otetaan kayttoon Output-pino.
    use Output;		
    
    #
    # SGML-dokumentti muunnetaan HTML-muotoon siten, etta se pilkotaan
    # useammaksi HTML-dokumentiksi. Muodostetut dokumentit nimetaan juoksevalla
    # numeroinnilla ID-alkuiseksi tai jos sita ei ole, niin oletusnimena on
    # node1.html...noden.html. 
    #
    
    # VAKIOT:
    # Paluuteksti ja -osoite kotisivulle
    $homepage = "http://www.cs.jyu.fi/~gelpo/index.html";
    $tohomepage = "Takaisin DigPubin kotisivulle";
    # Muunnosohjelman (pstogif) hakemisto.
    $conversion = "/u1/users/gelpo/latex/latex2html/latex2html-95.1/pstogif";
    # Paluu footnote-tiedostosta tekstiin.
    $footnote_return = "Takaisin tekstiin...";
    # Alaotsikoiden max.maara
    $subtitlemax = 100;
    
    # MUUTTUJAT: 
    # Kasiteltavan elementin ID.
    $current_id = '';	
    # Pino, joka sisaltaa elementtien ID:t.
    @current_id_stack = ();
    # Kaytettavan tulostiedoston nimi.
    $current_file = '';	
    # Tiedostonimet, joita on kaytetty.
    @current_file_stack = ();
    # Ylimmaisen elementin ID.
    $top_id = '';			
    # Ylimmaisen tiedoston ID.
    $top_file = '';
    # Edellisen tiedoston nimi.
    $previous_file = '';
    # Laskuri taulukoiden numerointia varten.
    $table_counter = 0;
    # Laskurit kuvien ja alaviitteiden numerointia varten.
    $figure_counter = 0;
    $footnote_counter = 0;
    $subtitleno = 0;
    # Nimi-muuttuja viittauksia varten.
    $name = "";
    # Laskuri liitteita varten.
    $appendix = 0;
    # Muuttuja paivamaaran tallennukseen.
    $date = "";
    
    #
    # 'start'- ja 'end'-elementteja kaytetaan viittausten kasittelyn
    # alussa ja lopussa.
    #
    sgml('start', sub { start_refs(); });
    sgml('end', sub { end_refs(); });
    
    # ARTICLE aloittaa ensimmaisen HTML-tiedoston.
    sgml('<ARTICLE>', sub {
        start_html(shift);
        $top_id = $current_id;
        $top_file = $current_file;
        $current_id = "toc";
        $previous_file = "toc.html";
    });
    sgml('</ARTICLE>', sub { end_html(); });
    
    sgml('<ARTHEADER>', "");
    sgml('</ARTHEADER>', "");
    
    #
    # Otsikoista muodostetaan viittaukset, paitsi kuvien otsikoista.
    #
    sgml('<TITLE>', sub { push_output 'string'; });
    sgml('</TITLE>', sub { 
        my $element = shift;
        if ($element->in(ARTHEADER)) {
            my $title = pop_output();
            output "\n<A NAME=\"$current_id\"><CENTER><H1>$title</H1></CENTER></A>\n";
        }
        elsif($element->in(FIGURE)) { 
            $Figure_counter++;
            my $title = pop_output(); 
            output "Kuva $Figure_counter. $title<br>"; }
        elsif($element->in(SECT1)) { # || $element->in(APPENDIX)) { 
            put_ref('title',$current_id,pop_output());
        }
        else { 
            my $title = pop_output();
            # Otsikot tallennetaan tunnisteella 'subtitle'+luvun numero
            # viittaustiedostoon.
            if($title) {
                $ref_name = "subtitle" . sprintf("%.20g",$subtitleno++);
                output "\n<A NAME=\"$name\"><H3>$title</H3></A>\n";
                put_ref($ref_name,$current_id,$title);
            }
        }
    });
    
    # Element: SUBTITLE
    sgml('<SUBTITLE>', "\n<CENTER><H2><I>");
    sgml('</SUBTITLE>', sub {
        require "ctime.pl";
        $date = &ctime(time);
        output "</I></H2></CENTER>\n<H4 ALIGN=CENTER>$date</H4>\n"; 
    });
    
    # Element: AUTHORGROUP
    sgml('<AUTHORGROUP>', "");
    sgml('</AUTHORGROUP>', "");
    
    # Element: AUTHOR
    sgml('<AUTHOR>', "");
    sgml('</AUTHOR>', "");
    
    # Element: COLLAB
    sgml('<COLLAB>', "");
    sgml('</COLLAB>', "");
    
    # Element: COLLABNAME
    sgml('<COLLABNAME>', "<CENTER>" );
    sgml('</COLLABNAME>', "</CENTER>" );
    
    # Element: FIRSTNAME
    # Tulostetaan vain etusivulle keskitetysti.
    sgml('<FIRSTNAME>', sub{ if($Title==1) { output "<CENTER><H3>";} });
    sgml('</FIRSTNAME>', "" );
    
    # Element: SURNAME
    # Peraan tulostetaan rivinvaihto etusivulla, muuten valilyonti.
    sgml('<SURNAME>', " " );
    sgml('</SURNAME>', sub { 
        if($Title==1 || $Title==2) 
        { 
            output "<br>"; 
            $Title++; 
        } 
        elsif($Title==3) { output "</H3></CENTER>\n"; $Title++; }
        else { output " "; }
    
    });
    
    # Element: ARTPAGENUMS
    # Ei kaytossa.
    sgml('<ARTPAGENUMS>', sub{ push_output 'nul'; });
    sgml('</ARTPAGENUMS>', sub { pop_output(); });
    
    # Element: BEGINPAGE
    sgml('<BEGINPAGE>', "");
    sgml('</BEGINPAGE>', "");
    
    # Element: ABSTRACT
    # Tiivistelma tulostettu kursiivilla.
    sgml('<ABSTRACT>', "<HR>\n<P><I>");
    sgml('</ABSTRACT>', "</I></P>\n<HR>\n");
    
    # Element: PARA
    sgml('<PARA>', "<P>");
    sgml('</PARA>', "</P>\n\n");
    
    # Element: CORPAUTHOR
    sgml('<CORPAUTHOR>', "<CENTER>");
    sgml('</CORPAUTHOR>', "</CENTER>\n");
    
    # Element: OTHERCREDIT
    sgml('<OTHERCREDIT>', "");
    sgml('</OTHERCREDIT>', "");
    
    # Element: HONORIFIC
    sgml('<HONORIFIC>', "");
    sgml('</HONORIFIC>', "");
    
    # SECT1:t aloittavat aina uuden HTML-dokumentin.
    # Element: SECT1
    sgml('<SECT1>',  sub { start_html(shift); });
    sgml('</SECT1>', sub { end_html(); });
    
    # Element: SECT2
    sgml('<SECT2>', sub { 
        my $element = shift;
        $name = lc( $element->attribute(ID)->value );
    });
    sgml('</SECT2>', "");
    
    # Element: SECT3
    sgml('<SECT3>', sub {
        my $element = shift;
        $name = lc( $element->attribute(ID)->value );
    });
    sgml('</SECT3>', "");
    
    # Element: SECT4
    sgml('<SECT4>', sub {
        my $element = shift;
        $name = lc( $element->attribute(ID)->value );
    });
    sgml('</SECT4>', "" ); 
    
    # Element: FIGURE
    sgml('<FIGURE>', "");
    sgml('</FIGURE>', "");
    
    # Element: ITEMIZEDLIST
    sgml('<ITEMIZEDLIST>', "<UL>" );
    sgml('</ITEMIZEDLIST>', "</UL>" );
    
    # Element: LISTITEM
    sgml('<LISTITEM>', "<LI>");
    sgml('</LISTITEM>', "");
    
    # Element: GRAPHIC
    # Viittaus kuvatiedostoon, jonka pitaisi olla .gif-muotoa.
    sgml('<GRAPHIC>', sub{
        my ($element,$event) = @_;
        my $file = $element->attribute('FILEREF')->value;
        # Kuvatiedosto muunnetaan ps-muodosta gif-muotoon, jos se on tarpeen.
        $tmp_file = $file;
        if($tmp_file=~ s/.ps/.gif/) { 
            unless ( -e $tmp_file ) {
                system("$conversion $file"); 
            }
            output "<IMG ALIGN=middle SRC=\"$tmp_file\">"; 
        }
        else { output "<IMG ALIGN=middle SRC=\"$file\">"; }
    });
    sgml('</GRAPHIC>', "");
    
    #
    # TAULUKOIDEN KASITTELY
    #
    # Muodostetaan viittaukset taulukkoon ja yllapidetaan taulukkolaskuria.
    #
    sgml('<TABLE>', sub {
        my $element = shift;
        push @current_id_stack, $current_id;
        $current_id = lc($element->attribute(ID)->value || gen_id());
        $table_counter++;
        put_ref('xref',$current_id,$table_counter);
        output "\n<H3>Taulukko $table_counter: " 
    	. get_ref('title',$current_id) . "</H3>\n\n";
        output "\n<table border=1 cellspacing=1 cellpadding=3>";
    });
    sgml('</TABLE>', sub {
        output "\n</table>\n";
        $current_id = pop @current_id_stack;
        $Thead = 0;
    });
    
    #
    # TGROUP-elementista haetaan sarakkeiden lukumaara. 
    #
    sgml('<TGROUP>', sub {
        my $element = shift;
        $Cols = $element->attribute('COLS')->value;
    });
    sgml('</TGROUP>', "");
    
    #
    # Kasvatetaan taulukon otsikkolaskuria.
    #
    sgml('<THEAD>', "");
    sgml('</THEAD>', sub { $Thead++; });
    
    # Element: TBODY
    sgml('<TBODY>', "");
    sgml('</TBODY>', "");
    
    #
    # Nollataan rivien ja sarakkeiden tulostuksessa apuna kaytettavat
    # muuttujat.
    #
    sgml('<ROW>', sub { 
        $cell_counter = 0;
        $Column = 0;
        output "<tr>";
    });
    sgml('</ROW>', "</tr>\n");
    
    #
    # Jos sarakkeen teksti on THEAD-elementin sisalla, se tulostetaan
    # taulukon otsikoksi, muuten tavalliseksi sarakkeeksi.
    # Taulukon rivien ensimmaiset sarakkeet tulostetaan hieman eri
    # maarityksilla kuin jalkimmaiset.
    #
    sgml('<ENTRY>', sub {
        if ($Thead==0) { output "<th>"; } 
        else { output "<td>"; }
    });
    sgml('</ENTRY>', sub {
        my $element = shift;
        if ($Thead == 0) {  output "</th>"; }
        else { output "</td>"; }
        $Column++;
    });
    
    # Element: COLSPEC
    sgml('<COLSPEC>', "");
    sgml('</COLSPEC>', "");
    
    #
    # Sisaiset viittaukset.
    #
    sgml('<LINK>', sub {
        my $element = shift;
        output "<A HREF=";
        output lc($element->attribute(XREFLABEL)->value) . ".html#" . lc($element->attribute(LINKEND)->value);
        output ">";
    });
    sgml('</LINK>', "</A>");
    
    #
    # Ulkoiset viittaukset.
    #
    # Element: ULINK
    sgml('<ULINK>', sub {
        my $element = shift;
        output "<A HREF=\" ";
        output $element->attribute('URL')->value;
        output "\">";
    });
    sgml('</ULINK>', "</A>");
    
    # Element: REFENTRY
    sgml('<REFENTRY>', "<P>");
    sgml('</REFENTRY>', "</P>");
    
    # Element: REFNAMEDIV
    sgml('<REFNAMEDIV>', "<P>");
    sgml('</REFNAMEDIV>', "</P>");
    
    # Element: REFNAME
    sgml('<REFNAME>', sub {
        my $element = shift;
        output "<P>";
        output "<A NAME=\"";
        output lc( $element->attribute(ID)->value );
        output "\">";
    });
    sgml('</REFNAME>', "</P>\n\n");
    
    # Element: REFPURPOSE
    sgml('<REFPURPOSE>', "");
    sgml('</REFPURPOSE>', "");
    
    # Element: REFSECT1
    sgml('<REFSECT1>', "");
    sgml('</REFSECT1>', "");
    
    # Element: QUOTE
    sgml('<QUOTE>', "<I>");
    sgml('</QUOTE>', "</I>");
    
    # Element: FOOTNOTEREF
    sgml('<FOOTNOTEREF>', sub { push_output 'string'; });
    sgml('</FOOTNOTEREF>', sub {
        my $element = shift;
        $fn_title = pop_output();
        $fn_id = $element->attribute(ID)->value;
        output "<A NAME=\"$fn_id\" HREF=\"";
        output lc($element->attribute(LINKEND)->value) . ".html";
        output "\">";
        output "$fn_title</A>";
    });
    
    
    # Element: FOOTNOTE
    # Footnote-tekstit tulostetaan erilliseen tiedostoon.
    sgml('<FOOTNOTE>', sub {
        my $element = shift;
        $fn_file = lc($element->attribute(ID)->value || gen_id()); 
        $fn_file .= ".html";
        push_output('file',$fn_file);
        output "<HTML>\n<HEAD>\n<TITLE>$fn_title</TITLE>\n</HEAD>\n<BODY>\n";
        output "<H2><I>$fn_title...</I></H2>\n<BR><HR>\n"; 
    });
    sgml('</FOOTNOTE>', sub { 
        output "<BR><HR><A HREF=\"";
        output "$current_file#$fn_id";
        output "\"><I>$footnote_return</I></A>";
        pop_output();
    });
    
    
    # Element: PROGRAMLISTING
    # Ohjelmalistat tulostetaan sisennettyna ja pienemmalla fontilla.
    sgml('<PROGRAMLISTING>', "<P>\n<PRE>");
    sgml('</PROGRAMLISTING>', "</PRE>\n</P>\n");
    
    # Element: APPENDIX
    # Kasvatetaan laskuria liitteiden lukumaaran mukaan.
    sgml('<APPENDIX>', sub { $appendix++; }); 
    sgml('</APPENDIX>', ""); 
    
    
    #
    # SDATA-elementtien kasittely.
    #
    sgml('|[TeX]|', "TeX");
    sgml('|[LaTeX]|', "LaTeX");
    sgml('|\"{a}|', "&auml;");
    sgml('|\"{A}|', "&Auml;");
    sgml('|\"{o}|', "&ouml;");
    sgml('|\"{O}|', "&Ouml;");
    sgml('|\%|', "%");
    sgml('|\_|', "_");
    sgml('|\&|', "&amp;");
    sgml('|\~|', "~");
    sgml('|\"{e}|', "&eacute;");
    sgml('|\^|', "^");
    sgml('|\<|', "&lt;");
    sgml('|\>|', "&gt;");
    sgml('|\$|', "\$");
    sgml('|\#|', "#");
    sgml('|\§|', "§");
    sgml('|\\\\|', "\\");
    
    
    #
    # Oletustoiminnot, jotka ilmoittavat mahd. puuttuvista maarittelyista.
    #
    sgml('start_element',sub { die "Unknown element: " . $_[0]->name; });
    sgml('sdata',sub { die "Unknown SDATA: " . $_[0]; });
    sgml('pi',sub { die "Unknown processing instruction: " . $_[0]; });
    sgml('start_subdoc',sub { die "Unknown subdoc entity: " . $_[0]->name; });
    
    ########################################################################
    # Ulkoisten entiteettien kasittely. Entiteettien on oltava CDATA-tyyp-
    # pia ja niiden sisaltamat tiedostot otetaan mukaan dokumenttiin ilman
    # suurempia muunnoksia.
    ########################################################################
    
    sgml('entity',sub {
        my $entity = shift;
    				# Kaytetaan systeemin luomaa
    				# tiedostonimea tai systeemi-ID:ta.
        my $filename = $entity->filenames->[0] || $entity->sysid;
    
    				# Kasitellaan vain CDATA-tyyppia.
        if ($entity->type eq 'CDATA') {
    	if (-r $filename) {
    	    unless (open INPUT, "<$filename") {
    		die "Cannot open external file $filename\n";
    	    }
    				# Muunnetaan erikoismerkit.
    	    while (<INPUT>) {
    		s/\&/\&amp;/g;
    		s/\</\&lt;/g;
    		s/\>/\&gt;/g;
    		output $_;
    	    }
    	    close INPUT;
    	} else {
    	    die "Cannot read file $filename\n";
    	}
        } else {
    	die "Cannot handle external entity with type " . $entity->type . "\n";
        }
    });
    
    ########################################################################
    # Muut kasittelyyn tarvittavat proseduurit.
    ########################################################################
    #
    # Uusi elementti aloittaa HTML-dokumentin.
    #
    sub start_html {
        my $element = shift;
        my $old_file = $current_file;
    
        # Vanhat arvot tallennetaan pinoon.
        push @current_id_stack, $current_id;
        push @current_file_stack, $current_file;
    
        # Muodostetaan uusi ID ja tiedosto.
        $current_id = lc($element->attribute(ID)->value || gen_id());
        $current_file = $current_id . '.html';
    
        # Huomioidaan edellinen taso, jos sellainen on.
        if ($previous_file) {
    	put_ref('previous',$current_file,$previous_file);
    	put_ref('next',$previous_file,$current_file);
        }
        $previous_file = '';
    
        # Laitetaan viittaus ylempaan tasoon.
        if ($old_file) {
    	put_ref('up',$current_file,$old_file);
        }
        else { $top_file = $current_file; }
    
        # Etsitaan otsikkoviittaus.
        my $plaintitle = my $title = get_ref('title',$current_id);
    
        # Muunnetaan otsikko sopivaksi.
        $plaintitle =~ s/\<[^\>]+\>//g;
    
        # Ellei kyseessa ole ylin taso, tulostetaan viittaus ennen
        # uuden tiedoston muodostamista.
        if ($old_file) {
    	output "<LI><A HREF=\"$current_file\">$plaintitle</A></LI>\n";
        }
    
        # Tulostus ohjataan uuteen tiedostoon.
        push_output('file',$current_file);
    
        # Tulostetaan alkujutut.
        output "<HTML>\n<I><A HREF=\"$homepage\">$tohomepage</A></I>\n";
        output "<HEAD>\n<TITLE>$plaintitle</TITLE>\n</HEAD>\n<BODY>\n";
    
        # Viittaukset muihin tasoihin, ellei kyseessa ole ylin taso.
        if ($old_file) {
    	my $up = get_ref('up',$current_file);
    	my $previous = get_ref('previous',$current_file);
    	my $next = get_ref('next',$current_file);
            output "<HR><BR>\n";
    	output "<A NAME=\"Seuraava\" HREF=$next><IMG ALIGN=BOTTOM ALT=\"Seuraava\" SRC=\"http://www.math.jyu.fi/kuvat/next.gif\"></A>\n" if $next;
    	output "<A NAME=\"Edellinen\" HREF=$previous><IMG ALIGN=BOTTOM ALT=\"Edellinen\" SRC=\"http://www.math.jyu.fi/kuvat/previous.gif\"></A>\n" if $previous;
    	output "<A NAME=\"Alkuun\" HREF=$up><IMG ALIGN=BOTTOM ALT=\"Alkuun\" SRC=\"http://www.math.jyu.fi/kuvat/top.gif\"></A>\n" if $up;
    
            output "\n<BR>\n";
            output "<A HREF=$next>Seuraava</A>\n" if $next;
            output "<A HREF=$previous>Edellinen</A>\n" if $previous;
            output "<A HREF=$top>Ylös</A>\n" if $top;
            output "<A HREF=$top_file>Alkuun</A>\n";
    	output "</P><HR>\n";
    
            # Tulostetaan luvun otsikot viittauksineen.
    	output "<P>\n";
            $title =~ s/\<A HREF=".*"\>//g;             
            $title =~ s/\<\/A\>//g;
            output "<LI><A HREF=#$current_id><H3>$title</H3></A>\n";
            $counter = 0;
            $appendix_counter = 1;
            while( $counter < $subtitlemax ){
                $subtitlename = "subtitle" . sprintf("%.20g",$counter++);
                $subtitle = get_ref( $subtitlename, $current_id );
                if($subtitle) {
                    # Poistetaan linkit otsikosta.
                    $subtitle =~ s/\<A HREF="\w*"\>//g;             
                    $subtitle =~ s/\<\/A\>//g;
    		# Muodostetaan nimi otsikkoviittauksille otsikon numerosta.
    		$reference = $subtitle;
                    @words = split(' ',$reference,2);  
                    $words[0] =~ s/\.//g;
    
                    if($appendix > 0) {
                        $reference = $current_id . $words[0];
                        output "<LI><A HREF=\"#$current_id$words[0]\">$subtitle</A>\n";
                    }
                    else {
                        output "<LI><A HREF=\"#luku$words[0]\">$subtitle</A>\n";
                    }
                }
            }
            output "</P><HR>\n"; 
        }
    
    
        # Etusivun otsikko tulostetaan keskitetysti, muuten reunaan.
        if ($Title == 0) {
            output "<HR>\n<A NAME=$current_id><CENTER><H1>$title</H1></CENTER></A>\n";
            $Title = 1;
        }
        else { output "<A NAME=$current_id><H1>$title</H1></A>\n"; }
    }
    
    ############################################################################
    # HTML-dokumentin lopetus.
    ############################################################################
    sub end_html {
    				
        # Paivitetaan edellisen ID:n ja tiedoston arvoja ja siirretaan
        # kasiteltava dokumentti 'edelliseksi'.
        $previous_file = $current_file;
        $current_id = pop @current_id_stack;
        $current_file = pop @current_file_stack;
    
        # Ellei kyseessa ole ylin taso, lisataan siirtymatiedot.
        if ($current_file) {
    	my $up = get_ref('up',$previous_file);
    	my $previous = get_ref('previous',$previous_file);
    	my $next = get_ref('next',$previous_file);
            output "<P><HR><BR>\n";
    	output "<A NAME=\"Seuraava\" HREF=$next><IMG ALIGN=BOTTOM ALT=\"Seuraava\" SRC=\"http://www.math.jyu.fi/kuvat/next.gif\"></A>" if $next;
    	output "<A NAME=\"Edellinen\" HREF=$previous><IMG ALIGN=BOTTOM ALT=\"Edellinen\" SRC=\"http://www.math.jyu.fi/kuvat/previous.gif\"></A>" if $previous;
    	output "<A NAME=\"Alkuun\" HREF=$up><IMG ALIGN=BOTTOM ALT=\"Ylös\" SRC=\"http://www.math.jyu.fi/kuvat/top.gif\"></A>" if $up;
    #	output "<A NAME=\"Alkuun\" HREF=$top_file><IMG ALIGN=BOTTOM ALT=\"Alkuun\" SRC=\"http://www.math.jyu.fi/kuvat/bookpage.gif\"></A>";
            output "\n<BR>\n";
    	output "<A HREF=$next>Seuraava</A>\n" if $next;
    	output "<A HREF=$previous>Edellinen</A>\n" if $previous;
    	output "<A HREF=$top_file>Alkuun</A>\n" if $up;
    	output "</P>\n\n";
        }
        else {
            output "\n<HR>";
            output "\n<I><A HREF=\"$homepage\">$tohomepage</A></I>";
        }
        pop_output();
    
    }
    
    ########################################################################
    # Ohjelmakoodit viittausten tekemiseen.
    ########################################################################
    
    # Taman muuttujan arvoa kasvatetaan aina, kun viittauksen arvo on muut-
    # tunut edellisen jasennyksen jalkeen.
    $refs_changed = 0;
    
    #
    # Proseduuri, jossa aloitetaan viittausten tekeminen. Avataan tiedosto,
    # johon viittaukset tallennetaan.
    #
    sub start_refs {
        my $file = shift || 'refs' . '.pl';
        if (-r $file) {
    	do $file || die "$@\n";
        }
        open REFS, ">$file" || die "$@\n";
    }
    
    
    #
    # Proseduuri, jossa paatetaan viittausten tekeminen. Tiedostoon
    # tulostetaan '1;', jonka se palauttaa avatessa. Lopuksi tiedosto
    # suljetaan ja ilmoitetaan muuttuneista viittauksista.
    #
    sub end_refs {
        print REFS "1;\n";
        close REFS;
        if ($refs_changed > 0) {
    	print STDERR "Warning: $refs_changed references have changed.\n"
        }
    }
    
    
    #
    # Proseduuri, joka etsii viittaukset. Argumentteja ovat $type, joka 
    # osoittaa viittauksen tyypin (esim. title), ja $id, joka osoittaa
    # viitattavan elementin ID:n.
    #
    sub get_ref {
        my ($type,$id) = @_;
        return $refs{$type}->{$id};
    }
    
    #
    # Proseduuri, jossa tallennetaan viittaukset erilliseen refs.pl-tiedostoon.
    # Lisaksi viittaus lisataan %refs-muuttujaan.
    #
    sub put_ref {
        my ($type,$id,$value) = @_;
        # Jos otsikkokentassa on tyhjaa, niin ei tehda viittauksia.
        if($value ne '')
        {
            if ($refs{$type}->{$id} ne $value && $refs{$type}->{$id} != $value) {
    	    $refs_changed++;
            }
            $refs{$type}->{$id} = $value;
            # Muunnetaan merkkiyhdistelmat \ ja ' ongelmien valttamiseksi.
            $type =~ s/(['\\])/\\\1/g;
            $id =~ s/(['\\])/\\\1/g;
            $value =~ s/(['\\])/\\\1/g;
            print REFS "\$refs\{'" . $type . "'\}->\{'" . $id . "'\} = '"
    		  . $value . "';\n";
        }
    }
    
    #
    # Generoidaan uusi ID-numero, ellei sita jo ole.
    #
    sub gen_id {
        $id_counter++;
        return "node$id_counter";
    }
    1;



    SeuraavaEdellinenYlös
    Seuraava Edellinen Alkuun