Mercurial > genshi > mirror
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 |