1
2 r"""
3 :Copyright:
4
5 Copyright 2006 - 2015
6 Andr\xe9 Malo or his licensors, as applicable
7
8 :License:
9
10 Licensed under the Apache License, Version 2.0 (the "License");
11 you may not use this file except in compliance with the License.
12 You may obtain a copy of the License at
13
14 http://www.apache.org/licenses/LICENSE-2.0
15
16 Unless required by applicable law or agreed to in writing, software
17 distributed under the License is distributed on an "AS IS" BASIS,
18 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 See the License for the specific language governing permissions and
20 limitations under the License.
21
22 ========================
23 Template Builder Logic
24 ========================
25
26 This module provides the logic to build a nodetree out of parser
27 events.
28 """
29 if __doc__:
30
31 __doc__ = __doc__.encode('ascii').decode('unicode_escape')
32 __author__ = r"Andr\xe9 Malo".encode('ascii').decode('unicode_escape')
33 __docformat__ = "restructuredtext en"
34
35 import codecs as _codecs
36
37 from ..._exceptions import TemplateEncodingError
38 from ... import interfaces as _interfaces
39 from ... import nodetree as _nodetree
40 from .. import _analyzer
41
42
44 """
45 HTML Template tree builder
46
47 :IVariables:
48 `_tree` : `nodetree.Root`
49 The built subtree
50
51 `_text` : ``list``
52 The current text buffer
53
54 `_tagstack` : ``list``
55 The stack of currently nested tag names with associated nodes
56
57 `_nodestack` : ``list``
58 The stack of currently nested snippet parameters
59
60 `_devnull` : ``bool``
61 Are we inside a removed element?
62
63 `encoding` : ``str``
64 Template encoding
65
66 `encoder` : `EncoderInterface`
67 Encoder
68
69 `decoder` : `DecoderInterface`
70 Decoder
71
72 `analyze` : `AttributeAnalyzerInterface`
73 Attribute analyzer
74 """
75 __implements__ = [_interfaces.BuilderInterface,
76 _interfaces.BuildingListenerInterface]
77
78 encoding = 'ascii'
79
80 - def __init__(self, encoder, decoder, analyzer=None):
81 """
82 Initialization
83
84 :Parameters:
85 `encoder` : ``callable``
86 Encoder factory
87
88 `decoder` : ``callable``
89 Decoder factory
90
91 `analyzer` : `AttributeAnalyzerInterface`
92 Attribute analyzer
93 """
94 root = _nodetree.Root()
95 self._tree = root
96 self._text = []
97 self._tagstack = []
98 self._nodestack = [root]
99 self._devnull = False
100 self.encoder = encoder(self.encoding)
101 self.decoder = decoder(self.encoding)
102 if analyzer is None:
103 analyzer = _analyzer.DEFAULT_ANALYZER(self.decoder, hidden=False)
104 self.analyze = analyzer
105
106 - def _flush_text(self):
107 """ Flush current text buffer """
108 if self._text:
109 if not self._devnull:
110 self._nodestack[-1].append_text(''.join(self._text))
111 self._text = []
112
113
114
115
116
117 - def handle_text(self, data):
118 """ :see: `ListenerInterface` """
119 if not self._devnull:
120 self._text.append(data)
121
123 """ :see: `ListenerInterface` """
124 if not self._devnull:
125 self._flush_text()
126 self._nodestack[-1].append_escape(escaped, data)
127
129 """ :see: `ListenerInterface` """
130 starttag = self.decoder.normalize(name)
131
132 if not self._devnull:
133 attr, special = self.analyze(attr)
134 if special:
135 self._flush_text()
136 flags, tdi = special.get('attribute', ('', None))
137 if not closed and tdi is None and flags == '-':
138 self._devnull = True
139 self._tagstack.append((starttag, '-'))
140 self._nodestack.append('-')
141 return
142
143 node = self._nodestack[-1].append_node(
144 name, attr, special, closed
145 )
146 if not closed:
147 self._tagstack.append((starttag, node))
148 self._nodestack.append(node)
149 return
150
151
152 if not closed and len(self._nodestack) > 1:
153
154 self._tagstack.append((starttag, None))
155 self.handle_text(data)
156
158 """ :see: `ListenerInterface` """
159 endtag = self.decoder.normalize(name)
160 tagstack = self._tagstack
161 if tagstack:
162 starttag, node = tagstack[-1]
163 if starttag == endtag:
164 tagstack.pop()
165
166
167 if node is not None:
168 self._flush_text()
169 node = self._nodestack.pop()
170 if self._devnull:
171 self._devnull = False
172 else:
173 node.endtag = data
174 return
175
176 self.handle_text(data)
177
181
183 """ :see: `ListenerInterface` """
184
185
186 self.handle_text(data)
187
189 """ :see: `ListenerInterface` """
190
191
192 self.handle_text(data)
193
195 """ :see: `ListenerInterface` """
196 self.handle_text(data)
197
198
199
200
201
217
218
219
220
221
223 """ :See: `tdi.interfaces.BuilderInterface` """
224 self._flush_text()
225 self._tree.finalize(self.encoder, self.decoder)
226 return self._tree
227