comparison genshi/template/markup.py @ 381:b9fc7a1f76ca trunk

Fix for #80: fallback only shown when the template to include wasn't found. In addition, the nesting of includes and fallback content should work correctly, and directives/expressions/etc inside fallback content are processed. Thanks to Christian Boos for the original patch and unit tests.
author cmlenz
date Wed, 29 Nov 2006 14:26:45 +0000
parents b146277eb54a
children e29a94b3ba0c
comparison
equal deleted inserted replaced
380:bf2068f5ef74 381:b9fc7a1f76ca
63 if loader: 63 if loader:
64 self.filters.append(self._include) 64 self.filters.append(self._include)
65 65
66 def _parse(self, source, encoding): 66 def _parse(self, source, encoding):
67 """Parse the template from an XML document.""" 67 """Parse the template from an XML document."""
68 stream = [] # list of events of the "compiled" template 68 streams = [[]] # stacked lists of events of the "compiled" template
69 dirmap = {} # temporary mapping of directives to elements 69 dirmap = {} # temporary mapping of directives to elements
70 ns_prefix = {} 70 ns_prefix = {}
71 depth = 0 71 depth = 0
72 in_fallback = False 72 in_fallback = 0
73 fallback_stream = None
74 include_href = None 73 include_href = None
75 74
76 if not isinstance(source, Stream): 75 if not isinstance(source, Stream):
77 source = XMLParser(source, filename=self.filename, 76 source = XMLParser(source, filename=self.filename,
78 encoding=encoding) 77 encoding=encoding)
79 78
80 for kind, data, pos in source: 79 for kind, data, pos in source:
80 stream = streams[-1]
81 81
82 if kind is START_NS: 82 if kind is START_NS:
83 # Strip out the namespace declaration for template directives 83 # Strip out the namespace declaration for template directives
84 prefix, uri = data 84 prefix, uri = data
85 ns_prefix[prefix] = uri 85 ns_prefix[prefix] = uri
136 if tag.localname == 'include': 136 if tag.localname == 'include':
137 include_href = new_attrs.get('href') 137 include_href = new_attrs.get('href')
138 if not include_href: 138 if not include_href:
139 raise TemplateSyntaxError('Include misses required ' 139 raise TemplateSyntaxError('Include misses required '
140 'attribute "href"', *pos) 140 'attribute "href"', *pos)
141 streams.append([])
141 elif tag.localname == 'fallback': 142 elif tag.localname == 'fallback':
142 in_fallback = True 143 in_fallback += 1
143 fallback_stream = []
144 144
145 else: 145 else:
146 stream.append((kind, (tag, new_attrs), pos)) 146 stream.append((kind, (tag, new_attrs), pos))
147 147
148 depth += 1 148 depth += 1
149 149
150 elif kind is END: 150 elif kind is END:
151 depth -= 1 151 depth -= 1
152 152
153 if in_fallback: 153 if in_fallback and data == self.XINCLUDE_NAMESPACE['fallback']:
154 if data == self.XINCLUDE_NAMESPACE['fallback']: 154 in_fallback -= 1
155 in_fallback = False
156 else:
157 fallback_stream.append((kind, data, pos))
158 elif data == self.XINCLUDE_NAMESPACE['include']: 155 elif data == self.XINCLUDE_NAMESPACE['include']:
159 stream.append((INCLUDE, (include_href, fallback_stream), pos)) 156 fallback = streams.pop()
157 stream = streams[-1]
158 stream.append((INCLUDE, (include_href, fallback), pos))
160 else: 159 else:
161 stream.append((kind, data, pos)) 160 stream.append((kind, data, pos))
162 161
163 # If there have have directive attributes with the corresponding 162 # If there have have directive attributes with the corresponding
164 # start tag, move the events inbetween into a "subprogram" 163 # start tag, move the events inbetween into a "subprogram"
180 stream.append((kind, data, pos)) 179 stream.append((kind, data, pos))
181 180
182 else: 181 else:
183 stream.append((kind, data, pos)) 182 stream.append((kind, data, pos))
184 183
185 return stream 184 assert len(streams) == 1
185 return streams[0]
186
187 def _prepare(self, stream):
188 for kind, data, pos in Template._prepare(self, stream):
189 if kind is INCLUDE:
190 data = data[0], list(self._prepare(data[1]))
191 yield kind, data, pos
186 192
187 def _include(self, stream, ctxt): 193 def _include(self, stream, ctxt):
188 """Internal stream filter that performs inclusion of external 194 """Internal stream filter that performs inclusion of external
189 template files. 195 template files.
190 """ 196 """
202 for event in tmpl.generate(ctxt): 208 for event in tmpl.generate(ctxt):
203 yield event 209 yield event
204 except TemplateNotFound: 210 except TemplateNotFound:
205 if fallback is None: 211 if fallback is None:
206 raise 212 raise
213 for filter_ in self.filters:
214 fallback = filter_(iter(fallback), ctxt)
207 for event in fallback: 215 for event in fallback:
208 yield event 216 yield event
209 else: 217 else:
210 yield event 218 yield event
211 219
Copyright (C) 2012-2017 Edgewall Software