# builder.py -*- coding: ISO-8859-1 -*- # # Copyright © 2000, 2002, 2004 Carey Evans. # # Permission to use, copy, modify, and distribute this software and # its documentation for any purpose and without fee is hereby granted, # provided that the above copyright notice appear in all copies and # that both that copyright notice and this permission notice appear in # supporting documentation. # # $Id: builder.py 26 2004-01-20 23:40:48Z carey $ """builder.py For a given input file, convert it to HTML and write it out. If the document contains stylesheet processing instructions, use that stylesheet first before converting CWML->HTML. """ import os, re, string, datetime import urlparse import libxml2, libxslt libxml2.lineNumbersDefault(1) libxml2.substituteEntitiesDefault(1) class PageBuilderError(Exception): pass class PageBuilder: def __init__(self): # Load the CWML to HTML stylesheet. xslpath = os.path.join(os.path.dirname(__file__), 'cwml.xsl') self.cwml_style = libxslt.parseStylesheetFile(xslpath) if self.cwml_style is None: raise PageBuilderError('Error loading default stylesheet.') def __del__(self): self.cwml_style.freeStylesheet() def build(self, page, src, dst): """Convert one page to HTML.""" # Load text or XML document from disk. if page.is_text(): doc = self.load_text(page, src) else: doc = libxml2.parseFile(src) if doc is None: raise PageBuilderError('Error loading ' + src) # Work out stylesheet parameters. mtime = self.get_doc_mtime(doc) if mtime is None: mtime = self.get_file_mtime(src) params = { 'root': "'%s'" % page.rootpath(), 'mtime': self.strparam(mtime), 'navtitle': self.strparam(page.title), 'navbar': self.strparam(self.navbar(page)) } # Process with stylesheet from PI, while present. pi_style = libxslt.loadStylesheetPI(doc) while pi_style is not None: newdoc = pi_style.applyStylesheet(doc, params) doc.freeDoc() pi_style.freeStylesheet() if newdoc is None: raise PageBuilderError( 'Error applying internal stylesheet to ' + src) doc = newdoc pi_style = libxslt.loadStylesheetPI(doc) # Process with CWML to HTML stylesheet. res = self.cwml_style.applyStylesheet(doc, params) doc.freeDoc() if res is None: raise PageBuilderError( 'Error applying default stylesheet to ' + src) self.cwml_style.saveResultToFilename(dst, res, False) res.freeDoc() def load_text(self, page, src): """Load a text document and wrap in XML.""" f = open(src, 'r') data = f.read() f.close() doc = libxml2.newDoc(None) top = doc.newChild(None, 'webpage', None) top.newTextChild(None, 'title', page.title) top.newTextChild(None, 'pre', data) return doc def strparam(self, s): return "'" + s.encode('utf-8').replace("'", "'") + "'" def navbar(self, page): return '||'.join(['|'.join(t) for t in page.navbar()]) def get_doc_mtime(self, doc): keyword = doc.xpathEval('string(/webpage/modified)') tok = keyword.split(' ') if len(tok) < 3: return None return tok[1] + 'T' + tok[2] def get_file_mtime(self, src): ts = datetime.datetime.fromtimestamp(os.path.getmtime(src)) return ts.isoformat()