"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