Package tdi :: Package markup :: Package soup :: Module builder
[frames] | no frames]

Source Code for Module tdi.markup.soup.builder

  1  # -*- coding: ascii -*- 
  2  # 
  3  # Copyright 2006 - 2013 
  4  # Andr\xe9 Malo or his licensors, as applicable 
  5  # 
  6  # Licensed under the Apache License, Version 2.0 (the "License"); 
  7  # you may not use this file except in compliance with the License. 
  8  # You may obtain a copy of the License at 
  9  # 
 10  #     http://www.apache.org/licenses/LICENSE-2.0 
 11  # 
 12  # Unless required by applicable law or agreed to in writing, software 
 13  # distributed under the License is distributed on an "AS IS" BASIS, 
 14  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 15  # See the License for the specific language governing permissions and 
 16  # limitations under the License. 
 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   
36 -class SoupBuilder(object):
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 ### ListenerInterface ################################################### 108 ######################################################################### 109
110 - def handle_text(self, data):
111 """ :see: `ListenerInterface` """ 112 if not self._devnull: 113 self._text.append(data)
114
115 - def handle_escape(self, escaped, data):
116 """ :see: `ListenerInterface` """ 117 if not self._devnull: 118 self._flush_text() 119 self._nodestack[-1].append_escape(escaped, data)
120
121 - def handle_starttag(self, name, attr, closed, data):
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 # Else: handle literal stuff. 145 if not closed and len(self._nodestack) > 1: 146 # need that for proper (un-)nesting 147 self._tagstack.append((starttag, None)) 148 self.handle_text(data)
149
150 - def handle_endtag(self, name, data):
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 # Handle endtag of processable node. 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
171 - def handle_comment(self, data):
172 """ :see: `ListenerInterface` """ 173 self.handle_text(data)
174
175 - def handle_msection(self, name, value, data):
176 """ :see: `ListenerInterface` """ 177 # pylint: disable = W0613 178 self.handle_text(data)
179
180 - def handle_decl(self, name, value, data):
181 """ :see: `ListenerInterface` """ 182 # pylint: disable = W0613 183 self.handle_text(data)
184
185 - def handle_pi(self, data):
186 """ :see: `ListenerInterface` """ 187 self.handle_text(data)
188 189 ######################################################################### 190 ### BuildingListenerInterface Extension ################################# 191 ######################################################################### 192
193 - def handle_encoding(self, encoding):
194 """ 195 :See: `tdi.interfaces.BuildingListenerInterface` 196 197 :Exceptions: 198 - `TemplateEncodingError` : encoding was not recognized 199 """ 200 try: 201 _codecs.lookup(encoding) 202 except LookupError, e: 203 raise TemplateEncodingError(str(e)) 204 if self.encoding != encoding: 205 self.encoding = encoding 206 self.encoder.encoding = encoding 207 self.decoder.encoding = encoding
208 209 ######################################################################### 210 ### BuilderInterface #################################################### 211 ######################################################################### 212
213 - def finalize(self):
214 """ :See: `tdi.interfaces.BuilderInterface` """ 215 self._flush_text() 216 self._tree.finalize(self.encoder, self.decoder) 217 return self._tree
218