# htmlDoc.py - Generate HTML documents # Version 1.0 - November 30, 1995 # Written by: # Joel Shprentz # BDM Federal, Inc. # 1501 BDM Way # McLean, VA 22102 # shprentz@bdm.com from string import * from sys import stdout import types # Augmented output file for rendering HTML class HtmlFile: maxLine = 70 def __init__ (self, aFile): self.outfile = aFile self.preformatted = 0 self.charCount = 0 self.lastWhite = 1 self.newline = 1 def startPreformatted (self): self.preformatted = self.preformatted + 1 def endPreformatted (self): if self.preformatted > 0: self.preformatted = self.preformatted - 1 def writePreformatted (self, text): self.outfile.write (text) self.charCount = HtmlFile.maxLine self.lastWhite = 0 self.newline = 0 def writeNewline (self): if self.newline == 0: self.outfile.write ("\n") self.charCount = 0 self.lastWhite = 1 self.newline = 1 def writeWhiteSpace (self): if self.lastWhite == 0: if self.charCount < HtmlFile.maxLine: self.outfile.write (" ") self.charCount = self.charCount + 1 self.lastWhite = 1 else: self.writeNewline () def writeUnsplittable (self, text): size = len (text) if size > 0: #if self.lastWhite and self.charCount + size > HtmlFile.maxLine: #self.writeNewline () self.outfile.write (text) self.charCount = self.charCount + size self.lastWhite = 0 self.newline = 0 def writeSplitText (self, text): if len (text) > 0: if len (strip (text[0])) == 0: self.writeWhiteSpace () words=split (text) if len (words) > 0: self.writeUnsplittable (words[0]) if len (words) > 1: for aWord in words [1:]: self.writeWhiteSpace () self.writeUnsplittable (aWord) if len (strip (text[len (text) - 1])) == 0: self.writeWhiteSpace () def write (self, text): if self.preformatted: self.writePreformatted (text) else: self.writeSplitText (text) def writeSpace (self): if self.preformatted: self.writePreformatted (" ") else: self.writeWhiteSpace () def writeAsIs (self, text): if self.preformatted: self.writePreformatted (" ") else: self.writeUnsplittable (text) # Attributes of tags class HtmlAttribute: def __init__ (self, aName, aNeedQuotes = 1): self.name = aName self.needQuotes = aNeedQuotes def writeToHtml (self, outfile, values): if values.has_key (self.name): value = values [self.name] outfile.writeSpace () outfile.writeAsIs (self.name) if value <> None: if self.needQuotes: outfile.writeAsIs ('="%s"' % value) else: outfile.writeAsIs ('=%s' % value) # Parent class for all HTML contents (abstract class) class HtmlContents: def writeHtml (self, outfile): self.writeToHtml (HtmlFile (outfile)) def writeToHtml (self, Htmlout): raise "HTMLException", "Implemented by subclass" def setFormValues (self, valueDict): pass # Whitespace contents - for efficiency, use theSpace class HtmlSpace (HtmlContents): def writeToHtml (self, outfile): outfile.writeSpace () theSpace = HtmlSpace () # Text contents - converts to valid HTML on output class HtmlText (HtmlContents): def __init__ (self, someText): self.text = someText def writeToHtml (self, outfile): pieces = splitfields (self.text, "&") outText = joinfields (pieces, "&") pieces = splitfields (outText, "<") outText = joinfields (pieces, "<") pieces = splitfields (outText, ">") outText = joinfields (pieces, ">") outfile.write (outText) # Tagged elements - contains start tag, attributes, contents, and end tag class HtmlElement (HtmlContents): def __init__ (self, aTag, someContents = None, needEnd=1, endLine=0, someDefaultAttributes = [], attributeDict = {}): self.tag = aTag self.needEndTag = needEnd self.tagEndsLine = endLine self.defaultAttributes = someDefaultAttributes self.attributes = attributeDict self.setContents (someContents) def append (self, anItem): if type (anItem) == types.StringType: self.contents.append (HtmlText (anItem)) elif type (anItem) == types.ListType: self.appendListContents (anItem) elif anItem: self.contents.append (anItem) def appendListContents (self, aList): for anItem in aList: self.append (anItem) def setContents (self, anItem): self.contents = [] self.append (anItem) def prepend (self, anItem): if type (anItem) == types.StringType: self.contents.insert (0, HtmlText (anItem)) elif type (anItem) == types.ListType: self.prependListContents (anItem) elif anItem: self.contents.insert (0, anItem) def prependListContents (self, aList): for anItem in aList.reverse (): self.prepend (anItem) def getAttribute (self, attributeName): return self.attributes [attributeName] def setAttribute (self, attributeName, attributeValue): self.attributes [attributeName] = attributeValue def writeStartTag (self, outfile): outfile.write ("<%s" % self.tag) for anAttribute in self.defaultAttributes: anAttribute.writeToHtml (outfile, self.attributes) outfile.write (">") def writeContents (self, outfile): for element in self.contents: element.writeToHtml (outfile) def writeToHtml (self, outfile): self.writeStartTag (outfile) self.writeContents (outfile) if self.needEndTag: outfile.write ("" % self.tag) if self.tagEndsLine: outfile.writeNewline () def setFormValues (self, valueDict): for element in self.contents: element.setFormValues (valueDict) # Class of preformatted HTML elements class HtmlPreformattedElement (HtmlElement): def writeContents (self, outfile): outfile.startPreformatted () HtmlElement.writeContents (self, outfile) outfile.endPreformatted () # Class of text-like form input fields class HtmlFormInputText (HtmlElement): def __init__ (self, type, name, value = None, size = None, maxlength = None): attributes = {"TYPE": type, "NAME": name} if value: attributes ["VALUE"] = value if size: attributes ["SIZE"] = size if maxlength: attributes ["MAXLENGTH"] = maxlength HtmlElement.__init__ (self, "INPUT", None, 0, 0, HtmlFormInputText.fieldAttributes, attributes) fieldAttributes = [ HtmlAttribute ("TYPE", 0), HtmlAttribute ("NAME", 0), HtmlAttribute ("SIZE", 0), HtmlAttribute ("MAXLENGTH", 0), HtmlAttribute ("VALUE") ] def setFormValues (self, valueDict): try: values = valueDict [self.getAttribute ("NAME")] self.setAttribute ("VALUE", values [0]) except: pass # Class text area fields class HtmlFormTextArea (HtmlPreformattedElement): def __init__ (self, name, cols, rows, contents = None): attributes = {"NAME": name, "COLS": cols, "ROWS": rows} HtmlPreformattedElement.__init__ (self, "TEXTAREA", contents, 1, 0, HtmlFormTextArea.fieldAttributes, attributes) fieldAttributes = [ HtmlAttribute ("NAME", 0), HtmlAttribute ("COLS", 0), HtmlAttribute ("ROWS", 0) ] def setFormValues (self, valueDict): try: values = valueDict [self.getAttribute ("NAME")] self.setContents (values [0]) except: pass # Class of checkbox and radio button form input fields class HtmlFormInputCheckBox (HtmlElement): def __init__ (self, type, name, value, contents = None, checked = 0): attributes = {"TYPE": type, "NAME": name, "VALUE": value} if checked: attributes ["CHECKED"] = None HtmlElement.__init__ (self, "INPUT", contents, 0, 0, HtmlFormInputCheckBox.fieldAttributes, attributes) fieldAttributes = [ HtmlAttribute ("TYPE", 0), HtmlAttribute ("NAME", 0), HtmlAttribute ("CHECKED"), HtmlAttribute ("VALUE") ] def setFormValues (self, valueDict): try: values = valueDict [self.getAttribute ("NAME")] if values.count (self.getAttribute ("VALUE")) > 0: self.setAttribute ("CHECKED", None) except: pass # Class of select lists class HtmlFormSelect (HtmlElement): def __init__ (self, name, contents = None, multiple = 0, size = None): attributes = {"NAME": name} if multiple: attributes ["MULTIPLE"] = None if size: attributes ["SIZE"] = size HtmlElement.__init__ (self, "SELECT", contents, 1, 0, HtmlFormSelect.fieldAttributes, attributes) fieldAttributes = [ HtmlAttribute ("TYPE", 0), HtmlAttribute ("NAME", 0), HtmlAttribute ("MULTIPLE"), HtmlAttribute ("SIZE", 0) ] def setFormValues (self, valueDict): try: values = valueDict [self.getAttribute ("NAME")] for element in self.contents: element.setOptionValues (values) except: pass # Class of select list options class HtmlFormOption (HtmlElement): def __init__ (self, contents = None, value = None, selected = 0): attributes = {} if value: attributes ["VALUE"] = value if selected: attributes ["SELECTED"] = None HtmlElement.__init__ (self, "OPTION", contents, 0, 1, HtmlFormOption.fieldAttributes, attributes) fieldAttributes = [ HtmlAttribute ("VALUE"), HtmlAttribute ("SELECTED") ] def setOptionValues (self, values): try: if values.count (self.getAttribute ("VALUE")) > 0: self.setAttribute ("SELECTED", None) except: pass # Class of image imput fields class HtmlFormInputImage (HtmlElement): def __init__ (self, name, source, align = "top"): attributes = {"TYPE": "IMAGE", "NAME": name, "SRC": source, "ALIGN": align} HtmlElement.__init__ (self, "INPUT", None, 0, 0, HtmlFormInputImage.fieldAttributes, attributes) fieldAttributes = [ HtmlAttribute ("TYPE", 0), HtmlAttribute ("NAME", 0), HtmlAttribute ("SRC"), HtmlAttribute ("ALIGN") ] # Class for submit and reset buttons class HtmlFormInputButton (HtmlElement): def __init__ (self, type, name = None, value = None): attributes = {"TYPE": type} if name: attributes ["NAME"] = name if value: attributes ["VALUE"] = value HtmlElement.__init__ (self, "INPUT", None, 0, 0, HtmlFormInputButton.fieldAttributes, attributes) fieldAttributes = [ HtmlAttribute ("TYPE", 0), HtmlAttribute ("NAME", 0), HtmlAttribute ("VALUE") ] # HTML Tag Factory Class class HtmlTagFactory: # These tags end with a newline def section (self, tag, contents = None): return HtmlElement (tag, contents, 1, 1) def HTML (self, contents = None): return self.section ("HTML", contents) def HEAD (self, contents = None): return self.section ("HEAD", contents) def TITLE (self, contents = None): return self.section ("TITLE", contents) def BODY (self, contents = None): return self.section ("BODY", contents) def P (self, contents = None): return self.section ("P", contents) def ADDR (self, contents = None): return self.section ("ADDR", contents) def BLOCKQUOTE (self, contents = None): return self.section ("BLOCKQUOTE", contents) def UL (self, contents = None): return self.section ("UL", contents) def OL (self, contents = None): return self.section ("OL", contents) def LI (self, contents = None): return self.section ("LI", contents) def DL (self, contents = None): return self.section ("DL", contents) # Definition list terms and definitions def DT (self, contents = None): return HtmlElement ("DT", contents, 0, 1) def DD (self, contents = None): return HtmlElement ("DD", contents, 0, 1) # Preformatted sections def preformatted (self, tag, contents = None): return HtmlPreformattedElement (tag, contents, 1, 1) def PRE (self, contents = None): return self.preformatted ("PRE", contents) # The heading tags def heading (self, tag, contents = None): return HtmlElement (tag, contents, 1, 1) def H1 (self, contents = None): return self.heading ("H1", contents) def H2 (self, contents = None): return self.heading ("H2", contents) def H3 (self, contents = None): return self.heading ("H3", contents) def H4 (self, contents = None): return self.heading ("H4", contents) def H5 (self, contents = None): return self.heading ("H5", contents) def H6 (self, contents = None): return self.heading ("H6", contents) # These tags mark phrases. They do not end the line. def phrase (self, tag, contents = None): return HtmlElement (tag, contents, 1, 0) def B (self, contents = None): return self.phrase ("B", contents) def I (self, contents = None): return self.phrase ("I", contents) def TT (self, contents = None): return self.phrase ("TT", contents) def CITE (self, contents = None): return self.phrase ("CITE", contents) def CODE (self, contents = None): return self.phrase ("CODE", contents) def EM (self, contents = None): return self.phrase ("EM", contents) def KBD (self, contents = None): return self.phrase ("KBD", contents) def SAMP (self, contents = None): return self.phrase ("SAMP", contents) def STRONG (self, contents = None): return self.phrase ("STRONG", contents) def VAR (self, contents = None): return self.phrase ("VAR", contents) # Miscellaneous tags def BR (self): return HtmlElement ("BR", None, 0, 1) def HR (self): return HtmlElement ("HR", None, 0, 1) # Anchor may have HREF and NAME attributes anchorAttributes = [ HtmlAttribute ("HREF"), HtmlAttribute ("NAME") ] def A (self, contents = None, href = None, name = None): attributes = {} if href <> None: attributes ["HREF"] = href if name <> None: attributes ["NAME"] = name return HtmlElement ("A", contents, 1, 0, HtmlTagFactory.anchorAttributes, attributes) # Image may have source and ISMAP attributes imageAttributes = [ HtmlAttribute ("SRC"), HtmlAttribute ("ALIGN"), HtmlAttribute ("ALT"), HtmlAttribute ("ISMAP") ] def IMG (self, source, alternate, align = "top", ismap = 0): attributes = { "SRC": source, "ALT": alternate, "ALIGN": align } if ismap: attributes ["ISMAP"] = None return HtmlElement ("IMG", None, 0, 0, HtmlTagFactory.imageAttributes, attributes) # Form has action and method attributes formAttributes = [ HtmlAttribute ("ACTION"), HtmlAttribute ("METHOD", 0), ] def FORM (self, contents = None, action = None, method = "GET"): attributes = { "METHOD": method} if action: attributes ["ACTION"] = action return HtmlElement ("FORM", contents, 1, 0, HtmlTagFactory.formAttributes, attributes) # Form fields have special classes def inputText (self, name, value = None, size = None, maxlength = None): return HtmlFormInputText ("TEXT", name, value, size, maxlength) def inputPassword (self, name, value = None, size = None, maxlength = None): return HtmlFormInputText ("PASSWORD", name, value, size, maxlength) def inputHidden (self, name, value = ""): return HtmlFormInputText ("HIDDEN", name, value) def inputCheckBox (self, name, value, contents = None, checked = 0): return HtmlFormInputCheckBox ("CHECKBOX", name, value, contents, checked) def inputRadioButton (self, name, value, contents = None, checked = 0): return HtmlFormInputCheckBox ("RADIO", name, value, contents, checked) def inputImage (self, name, source, align = "top"): return HtmlFormInputImage (name, source, align) def inputSubmit (self, name = None, value = "Submit"): return HtmlFormInputButton ("SUBMIT", name, value) def inputReset (self, value = "Reset"): return HtmlFormInputButton ("RESET", None, value) def SELECT (self, name, contents = None, multiple = 0, size = None): return HtmlFormSelect (name, contents, multiple, size) def OPTION (self, contents = None, value = None, selected = 0): return HtmlFormOption (contents, value, selected) def TEXTAREA (self, name, cols, rows, contents = None): return HtmlFormTextArea (name, cols, rows, contents) Tag = HtmlTagFactory () # HTML Document class HtmlDocument: def __init__ (self): self.htmlTitle = None self.contents = [] def setHtmlTitle (self, text): self.htmlTitle = text def prepend (self, moreContents): self.contents.insert (0, moreContents) def append (self, moreContents): self.contents.append (moreContents) # These methods construct various parts of the document def headTitle (self): if self.htmlTitle: return Tag.TITLE (self.htmlTitle) else: return Tag.TITLE ("Untitled document") def head (self): return Tag.HEAD (self.headTitle ()) def startBody (self): return None def endBody (self): return None def setFormValues (self, valueDict): for element in self.contents: element.setFormValues (valueDict) def writeHtml (self, outfile): body = Tag.BODY ([self.startBody (), self.contents, self.endBody ()]) doc = Tag.HTML ([self.head (), body]) doc.writeHtml (outfile) def printHtml (self): self.writeHtml (stdout)