1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """
18 ========================
19 Template Builder Logic
20 ========================
21
22 This module provides the logic to build a nodetree out of parser
23 events.
24 """
25 __author__ = u"Andr\xe9 Malo"
26 __docformat__ = "restructuredtext en"
27
28 import codecs as _codecs
29
30 from tdi._exceptions import TemplateEncodingError
31 from tdi import interfaces as _interfaces
32 from tdi import nodetree as _nodetree
33 from tdi.markup import _analyzer
34
35
37 """
38 HTML Template tree builder
39
40 :IVariables:
41 `_tree` : `nodetree.Root`
42 The built subtree
43
44 `_text` : ``list``
45 The current text buffer
46
47 `_tagstack` : ``list``
48 The stack of currently nested tag names with associated nodes
49
50 `_nodestack` : ``list``
51 The stack of currently nested snippet parameters
52
53 `_devnull` : ``bool``
54 Are we inside a removed element?
55
56 `encoding` : ``str``
57 Template encoding
58
59 `encoder` : `EncoderInterface`
60 Encoder
61
62 `decoder` : `DecoderInterface`
63 Decoder
64
65 `analyze` : `AttributeAnalyzerInterface`
66 Attribute analyzer
67 """
68 __implements__ = [_interfaces.BuilderInterface,
69 _interfaces.BuildingListenerInterface]
70
71 encoding = 'ascii'
72
73 - def __init__(self, encoder, decoder, analyzer=None):
74 """
75 Initialization
76
77 :Parameters:
78 `encoder` : ``callable``
79 Encoder factory
80
81 `decoder` : ``callable``
82 Decoder factory
83
84 `analyzer` : `AttributeAnalyzerInterface`
85 Attribute analyzer
86 """
87 root = _nodetree.Root()
88 self._tree = root
89 self._text = []
90 self._tagstack = []
91 self._nodestack = [root]
92 self._devnull = False
93 self.encoder = encoder(self.encoding)
94 self.decoder = decoder(self.encoding)
95 if analyzer is None:
96 analyzer = _analyzer.DEFAULT_ANALYZER(self.decoder, hidden=False)
97 self.analyze = analyzer
98
99 - def _flush_text(self):
100 """ Flush current text buffer """
101 if self._text:
102 if not self._devnull:
103 self._nodestack[-1].append_text(''.join(self._text))
104 self._text = []
105
106
107
108
109
110 - def handle_text(self, data):
111 """ :see: `ListenerInterface` """
112 if not self._devnull:
113 self._text.append(data)
114
116 """ :see: `ListenerInterface` """
117 if not self._devnull:
118 self._flush_text()
119 self._nodestack[-1].append_escape(escaped, data)
120
122 """ :see: `ListenerInterface` """
123 starttag = self.decoder.normalize(name)
124
125 if not self._devnull:
126 attr, special = self.analyze(attr)
127 if special:
128 self._flush_text()
129 flags, tdi = special.get('attribute', ('', None))
130 if not closed and tdi is None and flags == '-':
131 self._devnull = True
132 self._tagstack.append((starttag, '-'))
133 self._nodestack.append('-')
134 return
135
136 node = self._nodestack[-1].append_node(
137 name, attr, special, closed
138 )
139 if not closed:
140 self._tagstack.append((starttag, node))
141 self._nodestack.append(node)
142 return
143
144
145 if not closed and len(self._nodestack) > 1:
146
147 self._tagstack.append((starttag, None))
148 self.handle_text(data)
149
151 """ :see: `ListenerInterface` """
152 endtag = self.decoder.normalize(name)
153 tagstack = self._tagstack
154 if tagstack:
155 starttag, node = tagstack[-1]
156 if starttag == endtag:
157 tagstack.pop()
158
159
160 if node is not None:
161 self._flush_text()
162 node = self._nodestack.pop()
163 if self._devnull:
164 self._devnull = False
165 else:
166 node.endtag = data
167 return
168
169 self.handle_text(data)
170
174
176 """ :see: `ListenerInterface` """
177
178 self.handle_text(data)
179
181 """ :see: `ListenerInterface` """
182
183 self.handle_text(data)
184
186 """ :see: `ListenerInterface` """
187 self.handle_text(data)
188
189
190
191
192
208
209
210
211
212
214 """ :See: `tdi.interfaces.BuilderInterface` """
215 self._flush_text()
216 self._tree.finalize(self.encoder, self.decoder)
217 return self._tree
218