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

Source Code for Module tdi.markup.soup.builder

  1  # -*- coding: ascii -*- 
  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      # pylint: disable = redefined-builtin 
 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   
43 -class SoupBuilder(object):
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 # ListenerInterface ##################################################### 115 ######################################################################### 116
117 - def handle_text(self, data):
118 """ :see: `ListenerInterface` """ 119 if not self._devnull: 120 self._text.append(data)
121
122 - def handle_escape(self, escaped, data):
123 """ :see: `ListenerInterface` """ 124 if not self._devnull: 125 self._flush_text() 126 self._nodestack[-1].append_escape(escaped, data)
127
128 - def handle_starttag(self, name, attr, closed, data):
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 # Else: handle literal stuff. 152 if not closed and len(self._nodestack) > 1: 153 # need that for proper (un-)nesting 154 self._tagstack.append((starttag, None)) 155 self.handle_text(data)
156
157 - def handle_endtag(self, name, data):
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 # Handle endtag of processable node. 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
178 - def handle_comment(self, data):
179 """ :see: `ListenerInterface` """ 180 self.handle_text(data)
181
182 - def handle_msection(self, name, value, data):
183 """ :see: `ListenerInterface` """ 184 # pylint: disable = unused-argument 185 186 self.handle_text(data)
187
188 - def handle_decl(self, name, value, data):
189 """ :see: `ListenerInterface` """ 190 # pylint: disable = unused-argument 191 192 self.handle_text(data)
193
194 - def handle_pi(self, data):
195 """ :see: `ListenerInterface` """ 196 self.handle_text(data)
197 198 ######################################################################### 199 # BuildingListenerInterface Extension ################################### 200 ######################################################################### 201
202 - def handle_encoding(self, encoding):
203 """ 204 :See: `tdi.interfaces.BuildingListenerInterface` 205 206 :Exceptions: 207 - `TemplateEncodingError` : encoding was not recognized 208 """ 209 try: 210 _codecs.lookup(encoding) 211 except LookupError, e: 212 raise TemplateEncodingError(str(e)) 213 if self.encoding != encoding: 214 self.encoding = encoding 215 self.encoder.encoding = encoding 216 self.decoder.encoding = encoding
217 218 ######################################################################### 219 # BuilderInterface ###################################################### 220 ######################################################################### 221
222 - def finalize(self):
223 """ :See: `tdi.interfaces.BuilderInterface` """ 224 self._flush_text() 225 self._tree.finalize(self.encoder, self.decoder) 226 return self._tree
227