"Fossies" - the Fresh Open Source Software Archive

Member "Tahchee-1.0.0/Sources/tahchee/plugins/_kiwi/templates.py" (22 Oct 2009, 6623 Bytes) of package /linux/privat/old/tahchee-1.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "templates.py" see the Fossies "Dox" file reference documentation.

    1 #!/usr/bin/env python
    2 # Encoding: iso-8859-1
    3 # vim: tw=80 ts=4 sw=4 noet fenc=latin-1
    4 # -----------------------------------------------------------------------------
    5 # Project           :   Kiwi
    6 # -----------------------------------------------------------------------------
    7 # Author            :   Sebastien Pierre (SPE)           <sebastien@type-z.org>
    8 # -----------------------------------------------------------------------------
    9 # Creation date     :   06-Mar-2006
   10 # Last mod.         :   18-Oct-2006
   11 # -----------------------------------------------------------------------------
   12 
   13 import re, xml.dom
   14 import sys
   15 from formatting import *
   16 
   17 RE_EXPRESSION    =re.compile("\$\(([^\)]+)\)")
   18 
   19 __doc__ = """\
   20 The template module implements a simple way to convert an XML document to another
   21 format (HTML, text, whatever) by expanding very simple XPath-like expressions. Of
   22 course, it is a very-small subset of what you could do in XSLT, but it has a
   23 Python syntax and is very, very easy to use.
   24 
   25 At first, your define `convertXXX' functions where XXX is your case-sensitive
   26 tagName. All these functions should take an element as parameter and run the
   27 `process' function with the element and template string as parameter.
   28 
   29 Expressions like `$(XXX)' (XXX being the expression) in the template strings
   30 will be expanded by procesing the set of nodes indicated by the XXX expression.
   31 
   32  - $(*) will process all children
   33  - $(MyNode) will process only nodes with 'MyNode' tagName
   34  - $(MyParent/MyNode) will process only the children of MyParent named MyNode
   35  - $(MyNode:alt) will use the function `convertMyNode_alt' instead of the
   36    default 'convertMyNode', if available. This allows to setup 'processing
   37    modes' for your document (like table of content, references, etc).
   38  - $(MyNode:alt?) will use the function `convertMyNode_alt' if it is defined, or
   39    fallback to `convertMyNode`.
   40 
   41 """
   42 
   43 #------------------------------------------------------------------------------
   44 #
   45 #  Processing functions
   46 #
   47 #------------------------------------------------------------------------------
   48 
   49 class Processor:
   50     """The processor is the core of the template engine. You give it a Python
   51     module with "convert*" functions, and it will process it."""
   52 
   53     def __init__( self, module=None ):
   54         self.expressionTable = {}
   55         self.variables       = {}
   56 
   57     def register( self, name2functions ):
   58         """Fills the EXPRESSION_TABLE which maps element names to processing
   59         functions. This function is only useful when you implement your
   60         templates in the same way as the `kiwi2html` module, ie. with processing
   61         functions like `convertXXX_VVV` where `XXX` stands for the element name,
   62         and `_VVV` is the optional variant (selected by`$(element:variant)`).
   63         
   64         You may prefer to use the `registerElementProcessor` instead if you want
   65         to register a processor for an individual tag.
   66         """
   67         self.expressionTable = {}
   68         for name, function in name2functions.items():
   69             if name.startswith("convert"):
   70                 ename = name[len("convert"):]
   71                 ename = ename.replace("_", ":")
   72                 self.expressionTable[ename] = function
   73 
   74     def registerElementProcessor( self, function, elementName, variant=None  ):
   75         """Registers the given function to process the given element name and
   76         the given optional variant.
   77         
   78         Note that this will replace any previsously registered processor for the
   79         element and variant."""
   80         if variant: elementName += ":" + variant
   81         self.expressionTable[elementName] = function
   82 
   83     def resolveSet( self, element, names ):
   84         """Resolves the set of names in the given element. When ["Paragraph"] is
   85         given, then all child paragraph nodes of the current node will be returned,
   86         while ["Section", "Paragraph"] will return all paragraphs for all
   87         sections."""
   88         s = []
   89         if len(names) == 1:
   90             name = names[0]
   91             for child in element.childNodes:
   92                 if name != "*" and not child.nodeType == xml.dom.Node.ELEMENT_NODE: continue
   93                 if name == "*" or child.tagName == name: s.append(child)
   94         else:
   95             name = names[0]
   96             for child in element.childNodes:
   97                 if name != "*" and not child.nodeType == xml.dom.Node.ELEMENT_NODE: continue
   98                 if name == "*" or child.tagName == name: s.extend(self.resolveSet(child, names[1:]))
   99         return s
  100 
  101     def processElement( self, element, selector=None ):
  102         """Processes the given element according to the EXPRESSION_TABLE, using the
  103         given selector to select an alternative function."""
  104         selector_optional = False
  105         if selector and selector[-1] == "?":
  106             selector = selector[:-1]
  107             selector_optional = True
  108         if element.nodeType == xml.dom.Node.TEXT_NODE:
  109             return escapeHTML(element.data)
  110         elif element.nodeType == xml.dom.Node.ELEMENT_NODE:
  111             element._processor = self
  112             fname = element.nodeName
  113             if selector: fname += ":" + selector
  114             func  = self.expressionTable.get(fname)
  115             # There is a function for the element in the EXPRESSION TABLE
  116             if func:
  117                 return func(element)
  118             elif selector_optional:
  119                 self.processElement(element)
  120             # Otherwise we simply expand its text
  121             else:
  122                 return self.defaultProcessElement(element, selector)
  123         else:
  124             return ""
  125 
  126     def defaultProcessElement( self, element, selector ):
  127         """Default function for processing elements. This returns the text."""
  128         return "".join([self.processElement(e) for e in element.childNodes])
  129 
  130     def interpret( self, element, expression ):
  131         """Interprets the given expression for the given element"""
  132         assert self.expressionTable
  133         # =VARIABLE means that we replace the expression by the content of the
  134         # variable in the varibales directory
  135         if expression.startswith("="):
  136             vname = expression[1:].upper()
  137             return self.variables.get(vname) or ""
  138         # Otherwise, the expression is a node selection expression, which may also
  139         # have a selector
  140         elif expression.rfind(":") != -1:
  141             names, selector = expression.split(":")
  142         # There may be no selector as well
  143         else:
  144             names           = expression
  145             selector        = None
  146         names = names.split("/")
  147         r     = ""
  148         for element in self.resolveSet(element, names):
  149             r += self.processElement(element, selector)
  150         return r
  151 
  152     # SYNTAX: $(EXPRESSION)
  153     # Where EXPRESSION is a "/" separated list of element names, optionally followed
  154     # by a colon ':' and a name
  155     def process( self, element, text ):
  156         i = 0
  157         r = ""
  158         while i < len(text):
  159             m = RE_EXPRESSION.search(text, i)
  160             if not m:
  161                 r += text[i:]
  162                 break
  163             else:
  164                 r += text[i:m.start()]
  165             r+= self.interpret(element, m.group(1))
  166             i = m.end()
  167         return r
  168 
  169     def generate( self, xmlDocument, bodyOnly=False, variables={} ):
  170         self.variables = variables
  171         return self.processElement(xmlDocument.childNodes[0])
  172 
  173 # EOF