summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 205bf33)
raw | patch | inline | side by side (parent: 205bf33)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Thu, 21 Feb 2002 06:21:18 +0000 (06:21 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Thu, 21 Feb 2002 06:21:18 +0000 (06:21 +0000) |
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@644 57a73879-2fb5-44c3-a270-3262357dd7e2
tools/build_html | [new file with mode: 0755] | patch | blob |
tools/html.py | [new file with mode: 0644] | patch | blob |
diff --git a/tools/build_html b/tools/build_html
--- /dev/null
+++ b/tools/build_html
@@ -0,0 +1,39 @@
+#! /usr/bin/python
+
+import sys
+import os.path
+import glob
+import html
+import dps.utils
+try:
+ from restructuredtext import Parser
+except ImportError:
+ from dps.parsers.restructuredtext import Parser
+
+if sys.argv[1:] == '--help':
+ print """
+Usage: build_html
+
+Converts all structured text (.stx) files to html files.
+"""
+ sys.exit(1)
+
+def to_html(filename):
+ parser = Parser()
+ input = open(filename).read()
+ document = dps.utils.newdocument()
+ parser.parse(input, document)
+
+ formatter = html.DumbHTMLFormatter()
+ return formatter.format_document(document)
+
+
+for filename in glob.glob('*.stx'):
+ htmlfile = "%s.html" % os.path.splitext(filename)[0]
+ print "%s -> %s" % (filename, htmlfile)
+ f=open(htmlfile, 'wb')
+ f.write(to_html(filename))
+ f.close()
+
+
+
diff --git a/tools/html.py b/tools/html.py
--- /dev/null
+++ b/tools/html.py
@@ -0,0 +1,685 @@
+import cStringIO, cgi, sys, urllib
+import dps.utils
+try:
+ from restructuredtext import Parser
+except ImportError:
+ from dps.parsers.restructuredtext import Parser
+
+# TODO: enforce model?
+
+class DumbHTMLFormatter:
+ def __init__(self):
+ self.out = cStringIO.StringIO()
+ self.w = self.out.write
+ self.section = 0
+ self.closers = []
+
+ def format(self, node):
+ '''Format a node
+ '''
+ for entry in node:
+ self.formatOneTag(entry)
+
+ def formatOneTag(self, tag):
+ if tag.tagname == '#text':
+ meth = self.format__text
+ else:
+ meth = getattr(self, 'format_'+tag.tagname)
+ meth(tag)
+
+ #
+ # Root Element
+ #
+ # ((title, subtitle?)?, docinfo?, %structure.model;)
+ #
+ def format_document(self, document):
+ ''' ((title, subtitle?)?, docinfo?, %structure.model;)
+
+
+ '''
+ self.document = document
+ self.w('<html><head>\n')
+
+ n = 0
+
+ # See if there's a title
+ if document[n].tagname == 'title':
+ title = cgi.escape(document[n][0][0].data)
+ self.w('<title>%s</title>\n'%title)
+ n += 1
+ if document[n].tagname == 'subtitle':
+ title = cgi.escape(document[n][0][0].data)
+ self.w('<h1>%s</h1>'%title)
+ self.section += 1
+ n += 1
+
+ # Now see if there's biblio information
+
+ # see if there's a field_list at the start of the document
+ if document[n].tagname == 'docinfo':
+ self.format_docinfo(document[n])
+ n += 1
+
+ self.w('</head>\n<body>')
+
+ # now for the body
+ l = list(document)
+ for entry in l[n:]:
+ self.formatOneTag(entry)
+ self.w('</body>\n</html>')
+ return self.out.getvalue()
+
+ #
+ # Title Elements
+ #
+ def format_title(self, node):
+ self.w('<h%d>'%self.section)
+ if node.children: self.format(node)
+ self.w('</h%d>\n'%self.section)
+
+ def format_subtitle(self, node):
+ raise NotImplementedError, node
+
+ #
+ # Bibliographic Elements
+ #
+ def format_docinfo(self, node):
+ ''' (((%bibliographic.elements;)+, abstract?) | abstract)
+
+ bibliographic.elements:
+ author | authors | organization | contact | version | revision
+ | status | date | copyright
+ '''
+ if node.children: self.format(node)
+
+ def format_abstract(self, node):
+ content = urllib.quote(node[0].data)
+ self.w('<meta name="description" content="%s">\n'%content)
+
+ def format_author(self, node):
+ content = urllib.quote(node[0].data)
+ self.w('<meta name="author" content="%s">\n'%content)
+
+ def format_authors(self, node):
+ ''' ((author, organization?, contact?)+)
+ '''
+ self.w('<meta name="author" content="')
+ print node
+ self.w('">\n'%content)
+
+ def format_organization(self, node):
+ content = urllib.quote(node[0].data)
+ self.w('<meta name="organization" content="%s">\n'%content)
+
+# TODO: not in DTD
+# def format_keywords(self, node):
+# content = urllib.quote(node[0].data)
+# self.w('<meta name="keywords" content="%s">\n'%content)
+
+ def format_contact(self, node):
+ addr = urllib.quote(node[0].data)
+ self.w('<link rev="made" href="mailto:%s>\n'%addr)
+
+ def format_version(self, node):
+ addr = urllib.quote(node[0].data)
+ self.w('<meta name="version" content="%s">\n'%content)
+
+ def format_revision(self, node):
+ addr = urllib.quote(node[0].data)
+ self.w('<meta name="revision" content="%s">\n'%content)
+
+ def format_status(self, node):
+ addr = urllib.quote(node[0].data)
+ self.w('<meta name="status" content="%s">\n'%content)
+
+ def format_date(self, node):
+ addr = urllib.quote(node[0].data)
+ self.w('<meta name="date" content="%s">\n'%content)
+
+ def format_copyright(self, node):
+ addr = urllib.quote(node[0].data)
+ self.w('<meta name="copyright" content="%s">\n'%content)
+
+ #
+ # Structural Elements
+ #
+ # section
+ #
+ # structure.model:
+ # ( ((%body.elements; | transition)+, (%structural.elements;)*)
+ # | (%structural.elements;)+ )
+ #
+ def format_section(self, node):
+ self.w('<a name="%s"></a>'%urllib.quote(node.attributes['name']))
+ self.section += 1
+ if node.children: self.format(node)
+ self.section -= 1
+
+ def format_transition(self, node):
+ self.w('<hr>')
+
+ #
+ # Body Elements
+ #
+ # paragraph | literal_block | block_quote | doctest_block| table
+ # | figure | image | footnote
+ # | bullet_list | enumerated_list | definition_list | field_list
+ # | option_list
+ # | note | tip | hint | warning | error | caution | danger | important
+ # | target | substitution_definition | comment | system_message
+ #
+ #
+ def format_paragraph(self, node):
+ ''' %text.model;
+ '''
+ # TODO: there are situations where the <p> </p> are unnecessary
+ self.w('<p>')
+ if node.children: self.format(node)
+ self.w('</p>\n')
+
+ # Simple lists
+ def format_bullet_list(self, node):
+ ''' (list_item+)
+ bullet CDATA
+ '''
+ # TODO: handle attribute
+ self.w('<ul>\n')
+ if node.children: self.format(node)
+ self.w('</ul>\n')
+
+ def format_enumerated_list(self, node):
+ ''' (list_item+)
+ enumtype (arabic | loweralpha | upperalpha | lowerroman |
+ upperroman)
+ prefix CDATA
+ suffix CDATA
+ start CDATA
+ '''
+ # TODO: handle attributes
+ self.w('<ol>\n')
+ if node.children: self.format(node)
+ self.w('</ol>\n')
+
+ def format_list_item(self, node):
+ ''' (%body.elements;)+
+ '''
+ self.w('<li>')
+ if node.children: self.format(node)
+ self.w('</li>\n')
+
+ # Definition List
+ def format_definition_list(self, node):
+ ''' (definition_list_item+)
+ '''
+ self.w('<dl>\n')
+ if node.children: self.format(node)
+ self.w('</dl>\n')
+
+ def format_definition_list_item(self, node):
+ ''' (term, classifier?, definition)
+ '''
+ self.w('<dt>')
+ if node.children: self.format(node)
+
+ def format_term(self, node):
+ ''' %text.model;
+ '''
+ self.w('<span class="term">')
+ if node.children:self.format(node)
+ self.w('</span>')
+
+ def format_classifier(self, node):
+ ''' %text.model;
+ '''
+ # TODO: handle the classifier better
+ self.w('<span class="classifier">')
+ if node.children: self.format(node)
+ self.w('</span>')
+
+ def format_definition(self, node):
+ ''' (%body.elements;)+
+ '''
+ self.w('</dt>\n<dd>')
+ # TODO: this is way suboptimal!
+ first = 1
+ for child in node.children:
+ if child.tagname == 'paragraph' and first:
+ # just format the contents of the para
+ self.format(child)
+ else:
+ # format the whole tag
+ self.formatOneTag(child)
+ first = 0
+ self.w('</dd>\n')
+
+ # Field List
+ def format_field_list(self, node):
+ ''' (field+)
+ '''
+ self.w('<dl>')
+ if node.children: self.format(node)
+ self.w('</dl>')
+
+ def format_field(self, node):
+ ''' (field_name, field_argument*, field_body)
+ '''
+ self.w('<dt>')
+ if node.children: self.format(node)
+
+ def format_field_name(self, node):
+ ''' (#PCDATA)
+ '''
+ self.w('<span class="field_name">')
+ if node.children:self.format(node)
+ self.w('</span>')
+
+ def format_field_argument(self, node):
+ ''' (#PCDATA)
+ '''
+ self.w('<span class="field_argument">')
+ if node.children: self.format(node)
+ self.w('</span>')
+
+ def format_field_body(self, node):
+ ''' (%body.elements;)+
+ '''
+ self.w('</dt>\n<dd class="field_body">')
+ if node.children: self.format(node)
+ self.w('</dd>\n')
+
+ # Option List
+ def format_option_list(self, node):
+ ''' (option_list_item+)
+ '''
+ self.w('<table border=0 cellspacing=0 cellpadding=2><tr><th align="left" class="option_header">Option</th>\n')
+ self.w('<th align="left" class="option_header">Description</th></tr>\n')
+ if node.children: self.format(node)
+ self.w('</table>\n')
+
+ def format_option_list_item(self, node):
+ ''' (option+, description)
+ '''
+ self.w('<tr>')
+ if node.children: self.format(node)
+ self.w('</tr>\n')
+
+ def format_option(self, node):
+ ''' ((short_option | long_option | vms_option), option_argument?)
+ '''
+ self.w('<td align="left" valign="top" class="option">')
+ if node.children: self.format(node)
+ self.w('</td>')
+
+ def format_short_option(self, node):
+ ''' (#PCDATA)
+ '''
+ for option in node.children:
+ self.w('-%s'%cgi.escape(option.data))
+
+ def format_long_option(self, node):
+ ''' (#PCDATA)
+ '''
+ for option in node.children:
+ self.w('--%s'%cgi.escape(option.data))
+
+ def format_vms_option(self, node):
+ ''' (#PCDATA)
+ '''
+ for option in node.children:
+ self.w('/%s'%cgi.escape(option.data))
+
+ def format_option_argument(self, node):
+ ''' (#PCDATA)
+ '''
+ for option in node.children:
+ self.w('=%s'%cgi.escape(option.data))
+
+ def format_description(self, node):
+ ''' (%body.elements;)+
+ '''
+ self.w('<td align="left" valign="top" class="option_description">')
+ if node.children: self.format(node)
+ self.w('</td>\n')
+
+ # Literal Block
+ def format_literal_block(self, node):
+ self.w('<pre>')
+ if node.children: self.format(node)
+ self.w('</pre>\n')
+
+ # Block Quote
+ def format_block_quote(self, node):
+ # TODO: I believe this needs to be CSS'ified - blockquote is deprecated
+ self.w('<blockquote>')
+ if node.children: self.format(node)
+ self.w('</blockquote>\n')
+
+ # Doctest Block
+ def format_doctest_block(self, node):
+ self.w('<pre>')
+ if node.children: self.format(node)
+ self.w('</pre>\n')
+
+ # Note, tip, hint, warning, error, caution, danger, important
+ def format_note(self, node):
+ ''' (%body.elements;)+
+ '''
+ self.w('<span class="note">')
+ if node.children: self.format(node)
+ self.w('</span>')
+
+ def format_tip(self, node):
+ ''' (%body.elements;)+
+ '''
+ self.w('<span class="tip">')
+ if node.children: self.format(node)
+ self.w('</span>')
+
+ def format_hint(self, node):
+ ''' (%body.elements;)+
+ '''
+ self.w('<span class="hint">')
+ if node.children: self.format(node)
+ self.w('</span>')
+
+ def format_warning(self, node):
+ ''' (%body.elements;)+
+ '''
+ self.w('<span class="warning">')
+ if node.children: self.format(node)
+ self.w('</span>')
+
+ def format_error(self, node):
+ ''' (%body.elements;)+
+ '''
+ self.w('<span class="error">')
+ if node.children: self.format(node)
+ self.w('</span>')
+
+ def format_caution(self, node):
+ ''' (%body.elements;)+
+ '''
+ self.w('<span class="caution">')
+ if node.children: self.format(node)
+ self.w('</span>')
+
+ def format_danger(self, node):
+ ''' (%body.elements;)+
+ '''
+ self.w('<span class="danger">')
+ if node.children: self.format(node)
+ self.w('</span>')
+
+ def format_important(self, node):
+ ''' (%body.elements;)+
+ '''
+ self.w('<span class="important">')
+ if node.children: self.format(node)
+ self.w('</span>')
+
+ # Footnote
+ def format_footnote(self, node):
+ ''' (label?, (%body.elements;)+)
+ %auto.att;
+ '''
+ raise NotImplementedError, node
+
+ def format_label(self, node):
+ ''' (#PCDATA)
+ '''
+ for label in node.children:
+ self.w(cgi.escape(label.data))
+
+ # Target
+ def format_target(self, node):
+ ''' (%text.model;)
+ %reference.atts;
+ %anonymous.att;
+ '''
+ pass
+
+ # Substitution Definition
+ def format_substitution_definition(self, node):
+ ''' (%text.model;)
+ '''
+ raise NotImplementedError, node
+
+ # Comment
+ def format_comment(self, node):
+ ''' (#PCDATA)
+ %fixedspace.att;
+ '''
+ # TODO: handle attrs
+ self.w('<!--')
+ for data in node.children:
+ self.w(cgi.escape(data.data))
+ self.w('-->')
+
+ # Figure
+ def format_figure(self, node):
+ ''' (image, ((caption, legend?) | legend)
+ '''
+ raise NotImplementedError, node
+
+ def format_image(self, node):
+ ''' EMPTY
+ uri CDATA #REQUIRED
+ alt CDATA #IMPLIED
+ height NMTOKEN #IMPLIED
+ width NMTOKEN #IMPLIED
+ scale NMTOKEN #IMPLIED
+ '''
+ attrs = node.attributes
+ l = ['src="%(uri)s"'%attrs]
+ if attrs.has_key('alt'):
+ l.append('alt="%(alt)s"'%attrs)
+ if attrs.has_key('alt'):
+ l.append('alt="%(alt)s"'%attrs)
+ if attrs.has_key('height'):
+ l.append('height="%(height)s"'%attrs)
+ if attrs.has_key('width'):
+ l.append('width="%(width)s"'%attrs)
+ # TODO: scale
+ self.w('<img %s>'%(' '.join(l)))
+
+ def format_caption(self, node):
+ ''' %text.model;
+ '''
+ raise NotImplementedError, node
+
+ def format_legend(self, node):
+ ''' (%body.elements;)+
+ '''
+ raise NotImplementedError, node
+
+ # System Message
+ def format_system_message(self, node):
+ ''' (%body.elements;)+
+ level NMTOKEN #IMPLIED
+ type CDATA #IMPLIED
+ '''
+ self.w('<span class="system_message-%s">'%node.attributes['type'])
+ if node.children: self.format(node)
+ self.w('</span>')
+
+ #
+ # Tables:
+ # NOT IN DOM YET
+ #
+ def format_table(self, node):
+ '''
+ +------------------------+------------+----------+----------+
+ | Header row, column 1 | Header 2 | Header 3 | Header 4 |
+ | (header rows optional) | | | |
+ +========================+============+==========+==========+
+ | body row 1, column 1 | column 2 | column 3 | column 4 |
+ +------------------------+------------+----------+----------+
+ | body row 2 | Cells may span columns. |
+ +------------------------+------------+---------------------+
+ | body row 3 | Cells may | - Table cells |
+ +------------------------+ span rows. | - contain |
+ | body row 4 | | - body elements. |
+ +------------------------+------------+---------------------+
+ '''
+ self.w('<table border=1>\n')
+ if node.children: self.format(node)
+ self.w('</table>\n')
+
+ def format_tgroup(self, node):
+ # we get the number of columns, if that's important
+ if node.children: self.format(node)
+
+ def format_colspec(self, node):
+ # we get colwidth, but don't need it
+ pass
+
+ def format_thead(self, node):
+ for row in node.children:
+ self.w('<tr>')
+ for cell in row.children:
+ s = ''
+ attrs = cell.attributes
+ if attrs.has_key('morecols'):
+ s = s + ' colspan=%d'%(attrs['morecols']+1)
+ if attrs.has_key('morerows'):
+ s = s + ' rowspan=%d'%(attrs['morerows']+1)
+ self.w('<th valign="top" align="left"%s>'%s)
+ if cell.children: self.format(cell)
+ self.w('</th>\n')
+ self.w('</tr>\n')
+
+ def format_tbody(self, node):
+ for row in node.children:
+ self.w('<tr>')
+ for cell in row.children:
+ s = ''
+ attrs = cell.attributes
+ if attrs.has_key('morecols'):
+ s = s + ' colspan=%d'%(attrs['morecols']+1)
+ if attrs.has_key('morerows'):
+ s = s + ' rowspan=%d'%(attrs['morerows']+1)
+ self.w('<td valign="top" align="left"%s>'%s)
+ if cell.children: self.format(cell)
+ self.w('</td>\n')
+ self.w('</tr>\n')
+
+ #
+ # Inline Elements
+ #
+ # Inline elements occur within the text contents of body elements. Some
+ # nesting of inline elements is allowed by these definitions, with the
+ # following caveats:
+ # - An inline element may not contain a nested element of the same type
+ # (e.g. <strong> may not contain another <strong>).
+ # - Nested inline elements may or may not be supported by individual
+ # applications using this DTD.
+ # - The inline elements <footnote_reference>, <literal>, and <image> do
+ # not support nesting.
+ #
+ # What that means is that all of these take (%text.model;) except:
+ # literal (#PCDATA)
+ # footnote_reference (#PCDATA)
+ #
+ # text.model:
+ # (#PCDATA | %inline.elements;)*
+ #
+ def format_emphasis(self, node):
+ ''' (%text.model;)
+ '''
+ self.w('<em>')
+ if node.children: self.format(node)
+ self.w('</em>')
+
+ def format_strong(self, node):
+ ''' (%text.model;)
+ '''
+ self.w('<strong>')
+ if node.children: self.format(node)
+ self.w('</strong>')
+
+ def format_interpreted(self, node):
+ ''' (%text.model;)
+ type CDATA #IMPLIED
+ '''
+ pass #raise NotImplementedError, node
+
+ def format_literal(self, node):
+ ''' (#PCDATA)
+ '''
+ self.w('<tt>')
+ for literal in node.children:
+ self.w(cgi.escape(literal.data))
+ self.w('</tt>')
+
+ def format_reference(self, node):
+ ''' (%text.model;)
+ %reference.atts;
+ %anonymous.att;
+ '''
+ attrs = node.attributes
+ doc = self.document
+ ok = 1
+ print node
+ if attrs.has_key('refuri'):
+ self.w('<a href="%s">'%attrs['refuri'])
+ elif doc.explicit_targets.has_key(attrs['refname']):
+ # an external reference has been defined
+ ref = doc.explicit_targets[attrs['refname']]
+ if ref.attributes.has_key('refuri'):
+ self.w('<a href="%s">'%ref.attributes['refuri'])
+ else:
+ self.w('<a href="#%s">'%attrs['refname'])
+ elif doc.implicit_targets.has_key(attrs['refname']):
+ # internal reference
+ name = attrs['refname']
+ self.w('<a href="#%s">'%urllib.quote(name))
+ else:
+ ok = 0
+ self.w('<span class="formatter_error">target "%s" '
+ 'undefined</span>'%attrs['refname'])
+ if node.children: self.format(node)
+ if ok:
+ self.w('</a>')
+
+ def format_footnote_reference(self, node):
+ ''' (#PCDATA)
+ %reference.atts;
+ %auto.att;
+ '''
+ raise NotImplementedError, node
+
+ def format_substitution_reference(self, node):
+ ''' (%text.model;)
+ %refname.att;
+ '''
+ raise NotImplementedError, node
+
+ def format_problematic(self, node):
+ ''' (%text.model;)
+ '''
+ raise NotImplementedError, node
+
+ #
+ # Finally, #text
+ #
+ def format__text(self, node):
+ self.w(cgi.escape(node.data))
+
+
+def main(filename, debug=0):
+ parser = Parser()
+ input = open(filename).read()
+ document = dps.utils.newdocument()
+ parser.parse(input, document)
+ if debug == 1:
+ print document.pformat()
+ else:
+ formatter = DumbHTMLFormatter()
+ print formatter.format_document(document)
+
+if __name__ == '__main__':
+ if len(sys.argv) > 2:
+ main(sys.argv[1], debug=1)
+ else:
+ main(sys.argv[1])
+