DocBook 3 to HTML Converter [Updated DocBook to HTML Jadeware] version (1.3) Version: dbtohtml.dsl, v 1.3 1997/06/24 Author: Mark Burton Posted to CTS June 24, 1997 Title: Updated DocBook to HTML Jadeware Author: Mark Burton Date: 24 Jun 1997 12:38:01 +0100 Hi, I enclose an updated version (1.3) of my minimalist DocBook 3 to HTML convertor. This version automatically creates a TOC and an Index. The Index building is very slow, perhaps some kind soul will show me a better way. With the help of a small Perl script (also enclosed) the output is split into separate files (top-level and then one for each Chapter/Appendix). I will gratefully receive any bug reports and enhancements and issue further versions from time to time. regards, Mark O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n) O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n) O(n) O(n) O(n) Mark Burton O(n) O(n) Order N Ltd. O(n) O(n) Chorlton Lane Farm, Chorlton Lane, Malpas, Cheshire, SY14 7ES, UK. O(n) O(n) http://www.ordern.demon.co.uk/ O(n) O(n) O(n) O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n) O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n)O(n) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; dbtohtml.dsl - DSSSL style sheet for DocBook to HTML conversion (jadeware) ; ; Author : Mark Burton (markb@ordern.com) ; Created On : Fri Jun 13 18:21:14 1997 ; Last Modified By: Mark Burton ; Last Modified On: Tue Jun 24 11:39:23 1997 ; ; $Id: dbtohtml.dsl,v 1.3 1997/06/24 11:24:22 markb Exp $ ; ; ; Use this style sheet in conjunction with splithtml.pl to produce a separate ; file for each Chapter and Appendix. Perhaps like this: ; ; jade -d dbtohtml.dsl -t sgml < yourdoc.sgm | splithtml.pl yourdoc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; declare non-standard functions (declare-flow-object-class element "UNREGISTERED::James Clark//Flow Object Class::element") (declare-flow-object-class empty-element "UNREGISTERED::James Clark//Flow Object Class::empty-element") (declare-flow-object-class document-type "UNREGISTERED::James Clark//Flow Object Class::document-type") (declare-flow-object-class processing-instruction "UNREGISTERED::James Clark//Flow Object Class::processing-instruction") (declare-flow-object-class entity "UNREGISTERED::James Clark//Flow Object Class::entity") (declare-flow-object-class entity-ref "UNREGISTERED::James Clark//Flow Object Class::entity-ref") (declare-flow-object-class formatting-instruction "UNREGISTERED::James Clark//Flow Object Class::formatting-instruction") (declare-characteristic preserve-sdata? "UNREGISTERED::James Clark//Characteristic::preserve-sdata?" #f) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; variables (define %no-split-output% #f) (define %no-make-toc% #f) (define %no-make-index% #f) (define %no-shade-screen% #f) (define %html-public-id% "-//W3C//DTD HTML 3.2 Final//EN") (define %output-basename% "DOCPART") (define %output-suffix% ".html") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; top-level sections (element BOOK (cond (%no-split-output% (make sequence (make document-type name: "html" public-id: %html-public-id%) (make element gi: "HTML" (make sequence (make element gi: "HEAD" (make element gi: "TITLE" (with-mode extract-title-text (process-first-descendant "TITLE")))) (make element gi: "BODY" (make sequence (process-children) (cond ((not %no-make-index%) (make sequence (make-fat-rule) (make-index))) (#t (empty-sosofo))))))))) (#t (make sequence (make-split-file (string-append %output-basename% %output-suffix%) (make sequence (process-first-descendant "TITLE") (process-first-descendant "BOOKINFO"))) (process-matching-children "PREFACE" "CHAPTER" "APPENDIX") (cond ((not %no-make-index%) (make-split-file (string-append %output-basename% "-INDEX" %output-suffix%) (make-index))) (#t (empty-sosofo))))))) (define (make-split-file file-name content) (make sequence (make formatting-instruction data: (string-append "<" "!-- " "Start of " file-name " -->")) (make document-type name: "html" public-id: %html-public-id%) (make element gi: "HTML" (make sequence (make element gi: "HEAD" (make element gi: "TITLE" (with-mode extract-title-text (process-first-descendant "TITLE")))) (make element gi: "BODY" (make sequence (make-anchor) content)))) (make formatting-instruction data: (string-append "<" "!-- " "End of " file-name " -->")))) (define (make-pref-chap-app) (cond (%no-split-output% (make sequence (make-anchor) (make-fat-rule) (process-children))) (#t (make-split-file (link-file-name (current-node)) (process-children))))) (element PREFACE (make-pref-chap-app)) (element CHAPTER (make-pref-chap-app)) (element APPENDIX (make-pref-chap-app)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; sections (element SECT1 (make sequence (make-anchor) (process-children))) (element SECT2 (make sequence (make-anchor) (process-children))) (element SECT3 (make sequence (make-anchor) (process-children))) (element SECT4 (make sequence (make-anchor) (process-children))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; titles (mode extract-title-text (element (TITLE) (process-children))) (element (BOOK TITLE) (make sequence (make element gi: "CENTER" (make element gi: "H1" (process-children))))) (element (CHAPTER TITLE) (make element gi: "H1" (make sequence (literal (chap-app-head-label "Chapter")) (process-children-trim)))) (element (APPENDIX TITLE) (make element gi: "H1" (make sequence (literal (chap-app-head-label "Appendix")) (process-children-trim)))) (element (SECT1 TITLE) (make element gi: "H2")) (element (SECT2 TITLE) (make element gi: "H3")) (element (SECT3 TITLE) (make element gi: "H4")) (element (SECT4 TITLE) (make element gi: "H5")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; font changers (element EMPHASIS (make element gi: "I")) (element TYPE (make element gi: "B" (make element gi: "TT"))) (element TOKEN (make element gi: "I" (make element gi: "B" (make element gi: "TT")))) (element REPLACEABLE (make element gi: "I")) (element FIRSTTERM (make element gi: "I")) (element APPLICATION (make element gi: "TT")) (element FILENAME (make element gi: "TT")) (element LITERAL (make element gi: "TT")) (element ENVAR (make element gi: "TT")) (element SUBSCRIPT (make element gi: "SUB")) (element SUPERSCRIPT (make element gi: "SUP")) (element CITETITLE (make element gi: "I")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; paragraph like things (element WARNING (make-special-para "WARNING:")) (element NOTE (make-special-para "NOTE:")) (element PARA (make sequence (make empty-element gi: "P") (with-mode footnote-ref (process-children)) (with-mode footnote-def (process-matching-children "FOOTNOTE")))) (element BLOCKQUOTE (make element gi: "BLOCKQUOTE")) (element SCREEN (let ((gubbins (make element gi: "PRE" (process-children)))) (make sequence (make empty-element gi: "P") (if %no-shade-screen% gubbins (make element gi: "TABLE" attributes: '(("border" "0") ("bgcolor" "#E0E0E0") ("width" "100%")) (make element gi: "TR" (make element gi: "TD" gubbins))))))) (element PHRASE (process-children)) (mode footnote-ref (element FOOTNOTE (make sequence (literal "[") (literal (format-number (element-number (current-node)) "1")) (literal "]")))) (mode footnote-def (element FOOTNOTE (make element gi: "BLOCKQUOTE" (make sequence (literal "[") (literal (format-number (element-number (current-node)) "1")) (literal "]") (process-children))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; lists (element ITEMIZEDLIST (make sequence (make empty-element gi: "P") (make element gi: "UL"))) (element ORDEREDLIST (make sequence (make empty-element gi: "P") (make element gi: "OL"))) (element (ITEMIZEDLIST LISTITEM) (make sequence (make empty-element gi: "LI") (process-children) (make empty-element gi: "P"))) (element (ORDEREDLIST LISTITEM) (make sequence (make empty-element gi: "LI") (process-children) (make empty-element gi: "P"))) (element VARIABLELIST (make sequence (make empty-element gi: "P") (make element gi: "DL"))) (element VARLISTENTRY (make sequence (make empty-element gi: "DT") (process-children))) (element (VARLISTENTRY LISTITEM) (make sequence (make empty-element gi: "DD") (process-children) (make empty-element gi: "P"))) (element TERM (process-children)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; index (define (index-entry-name indexterm) (string-append "index." (format-number (element-number indexterm) "1"))) (element INDEXTERM (make sequence (make element gi: "A" attributes: (list (list "name" (index-entry-name (current-node)))) (literal "")) (empty-sosofo))) ; DIY string>? (define (string>? s1 s2) (let ((len1 (string-length s1)) (len2 (string-length s2))) (let loop ((i 0)) (cond ((= i len1) #f) ((= i len2) #t) (#t (let ((c1 (index-char-val (string-ref s1 i))) (c2 (index-char-val (string-ref s2 i)))) (cond ((= c1 c2) (loop (+ i 1))) (#t (> c1 c2))))))))) (define (index-char-val ch) (case ch ((#\A #\a) 65) ((#\B #\b) 66) ((#\C #\c) 67) ((#\D #\d) 68) ((#\E #\e) 69) ((#\F #\f) 70) ((#\G #\g) 71) ((#\H #\h) 72) ((#\I #\i) 73) ((#\J #\j) 74) ((#\K #\k) 75) ((#\L #\l) 76) ((#\M #\m) 77) ((#\N #\n) 78) ((#\O #\o) 79) ((#\P #\p) 80) ((#\Q #\q) 81) ((#\R #\r) 82) ((#\S #\s) 83) ((#\T #\t) 84) ((#\U #\u) 85) ((#\V #\v) 86) ((#\W #\w) 87) ((#\X #\x) 88) ((#\Y #\y) 89) ((#\Z #\z) 90) ((#\ ) 32) ((#\0) 48) ((#\1) 49) ((#\2) 50) ((#\3) 51) ((#\4) 52) ((#\5) 53) ((#\6) 54) ((#\7) 55) ((#\8) 56) ((#\9) 57) ; laziness precludes me from filling this out further (else 0))) ; return the string data for a given index entry (define (get-index-entry-data entry) (let ((primary (select-elements (descendants entry) "PRIMARY")) (secondary (select-elements (descendants entry) "SECONDARY"))) (if (node-list-empty? secondary) (data primary) (string-append (data primary) " - " (data secondary))))) ; insert a pair of the form (index-string . index-markup) into the ; tree of index entries -- each tree node is a three element list (L PAIR R) (define (insert-index-entry tree entry) (let* ((text (get-index-entry-data entry)) (pear (cons text (make sequence (make empty-element gi: "LI") (make element gi: "A" attributes: (list (list "href" (string-append (link-file-name entry) "#" (index-entry-name entry)))) (literal text)))))) (insert-index-entry-helper pear tree))) (define (insert-index-entry-helper pear tree) (cond ((null? tree) (list (list) pear (list))) ((string>? (car pear) (car (car (cdr tree)))) (list (car tree) (car (cdr tree)) (insert-index-entry-helper pear (car (cdr (cdr tree)))))) (#t (list (insert-index-entry-helper pear (car tree)) (car (cdr tree)) (car (cdr (cdr tree))))))) ; build the sorted list and then filter out the markup (define (make-index) (letrec ((traverse (lambda (node) (cond ((null? node) (empty-sosofo)) (#t (sosofo-append (traverse (car node)) (cdr (car (cdr node))) (traverse (car (cdr (cdr node)))))))))) (make sequence (make element gi: "A" attributes: (list (list "name" "INDEXTOP")) (literal "")) (make element gi: "H1" (literal "Index")) (make element gi: "UL" (traverse (node-list-reduce (select-elements (subtree (current-node)) "INDEXTERM") insert-index-entry '())))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; links & cross-references (define (link-file-name target) (cond (%no-split-output% "") (#t (string-append %output-basename% "-" (cond ((equal? (gi target) "CHAPTER") (format-number (child-number target) "1")) ((ancestor-child-number "CHAPTER" target) (format-number (ancestor-child-number "CHAPTER" target) "1")) ((equal? (gi target) "APPENDIX") (format-number (child-number target) "A")) ((ancestor-child-number "APPENDIX" target) (format-number (ancestor-child-number "APPENDIX" target) "A")) (#t "")) %output-suffix%)))) (element LINK (let* ((target (element-with-id (attribute-string "linkend") (ancestor "BOOK"))) (target-file-name (link-file-name target))) (make element gi: "A" attributes: (list (list "href" (string-append target-file-name "#" (attribute-string "linkend"))))))) (element ULINK (make element gi: "A" attributes: (list (list "href" (attribute-string "url"))))) (element XREF (let* ((target (element-with-id (attribute-string "linkend") (ancestor "BOOK"))) (target-file-name (link-file-name target))) (make element gi: "A" attributes: (list (list "href" (string-append target-file-name "#" (attribute-string "linkend")))) (with-mode extract-xref-text (process-node-list target))))) (mode extract-xref-text (default (let ((title-sosofo (with-mode extract-title-text (process-first-descendant "TITLE")))) (if (sosofo? title-sosofo) title-sosofo (literal (string-append "Reference to " (gi))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; figures (element FIGURE (make sequence (make empty-element gi: "P") (make-anchor) (process-children) (make empty-element gi: "P"))) (element (FIGURE TITLE) (make sequence (make element gi: "B") (make empty-element gi: "P"))) (element GRAPHIC (let ((img (make sequence (make empty-element gi: "P") (make empty-element gi: "IMG" attributes: (list (list "src" (attribute-string "fileref"))))))) (if (equal? (attribute-string "align") "CENTER") (make element gi: "CENTER" img) img))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; tables (element INFORMALTABLE (make sequence (make empty-element gi: "P") (make element gi: "TABLE" attributes: (if (equal? (attribute-string "frame") "ALL") '(("border" "2") ("cellpadding" "2")) '())) (make empty-element gi: "P"))) (element TGROUP (process-children)) (element THEAD (process-children)) (element (THEAD ROW) (make sequence (make empty-element gi: "TR") (process-children))) (element (THEAD ROW ENTRY) (make sequence (make empty-element gi: "TD") (make element gi: "B" (process-children)))) (element TBODY (process-children)) (element (TBODY ROW) (make sequence (make empty-element gi: "TR") (process-children))) (element (TBODY ROW ENTRY) (make sequence (make empty-element gi: "TD") (process-children))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; book info (element BOOKINFO (make sequence (make element gi: "CENTER" (process-children)) (cond ((not %no-make-toc%) (make sequence (make-fat-rule) (make element gi: "H2" (literal "Contents")) (make element gi: "ul" (with-mode make-toc-links (process-node-list (ancestor "BOOK")))))) (#t (empty-sosofo))))) (element BOOKBIBLIO (process-children)) (element AUTHORGROUP (make sequence (make empty-element gi: "P") (process-children))) (element AUTHOR (process-children)) (element FIRSTNAME (make element gi: "B")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; TOC (element LOF (empty-sosofo)) (element LOT (empty-sosofo)) (element TOC (empty-sosofo)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; DIY TOC (mode make-toc-links (element (BOOK) (sosofo-append (process-children) (cond ((not %no-make-index%) (make sequence (make empty-element gi: "LI") (make element gi: "A" attributes: (list (list "href" (string-append %output-basename% "-INDEX" %output-suffix% "#INDEXTOP"))) (literal "Index")))) (#t (empty-sosofo))))) (element (CHAPTER) (make-chap-or-app-toc-links)) (element (APPENDIX) (make-chap-or-app-toc-links)) (element (SECT1) (make sequence (make empty-element gi: "LI") (let ((title-text (with-mode extract-title-text (process-first-descendant "TITLE")))) (if (id) (make element gi: "A" attributes: (list (list "href" (string-append (link-file-name (current-node)) "#" (id)))) title-text) title-text)))) (default (empty-sosofo))) (define (make-chap-or-app-toc-links) (make sequence (make empty-element gi: "LI") (let ((title-text (make sequence (literal (if (equal? (gi) "CHAPTER") (string-append "Chapter " (format-number (element-number (current-node)) "1") " - ") (string-append "Appendix " (format-number (element-number (current-node)) "A") " - "))) (with-mode extract-title-text (process-first-descendant "TITLE"))))) (if (id) (make element gi: "A" attributes: (list (list "href" (string-append (link-file-name (current-node)) "#" (id)))) title-text) title-text)) (make element gi: "UL" (with-mode make-toc-links (process-matching-children "SECT1"))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; local additions (element HRULE (make empty-element gi: "HR")) (element BOLD (make element gi: "B")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; make the unimplemented bits stand out (default (make element gi: "FONT" attributes: '(("color" "red")))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; standard subroutines (define (node-list-reduce nl combine init) (if (node-list-empty? nl) init (node-list-reduce (node-list-rest nl) combine (combine init (node-list-first nl))))) (define (subtree nl) (node-list-map (lambda (snl) (node-list snl (subtree (children snl)))) nl)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; various homebrew subroutines (define (make-fat-rule) (make empty-element gi: "HR" attributes: '(("size" "5")))) (define (chap-app-head-label chap-or-app) (let ((label (attribute-string "label" (ancestor chap-or-app)))) (string-append chap-or-app " " (if label (if (equal? label "auto") (format-number (element-number (ancestor chap-or-app)) (if (equal? chap-or-app "Chapter") "1" "A")) label) (format-number (element-number (ancestor chap-or-app)) (if (equal? chap-or-app "Chapter") "1" "A"))) ". "))) (define (make-anchor) (if (id) (make element gi: "A" attributes: (list (list "name" (id))) (literal "")) (empty-sosofo))) (define (make-special-para label) (make sequence (make empty-element gi: "P") (make element gi: "B" (literal label)) (make element gi: "BLOCKQUOTE" (process-children)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; the end [Image] Content-Type: application/octet-stream Content-Transfer-Encoding: 7bit #!/usr/local/bin/perl # splithtml.pl - Perl script to split Jade output into separate HTML files # # Author : Mark Burton (markb@ordern.com) # Created On : Tue Jun 24 10:52:42 1997 # Last Modified By: Mark Burton # Last Modified On: Tue Jun 24 10:58:21 1997 $docpart = "DOCPART"; if(@ARGV) { $basename = $ARGV[0]; shift; } $gubbins = (join "", <>); while ($gubbins =~ /(.*)/gs) { if($basename) { $filename = ">$1"; $chunk = $2; $filename =~ s/$docpart/$basename/; open OUT, $filename; $chunk =~ s/$docpart/$basename/gs; print OUT $chunk; } else { open OUT, ">$1"; print OUT $2; } close OUT; } exit 0;