diff 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
line wrap: on
line diff
--- a/genshi/template/markup.py
+++ b/genshi/template/markup.py
@@ -65,12 +65,11 @@
 
     def _parse(self, source, encoding):
         """Parse the template from an XML document."""
-        stream = [] # list of events of the "compiled" template
+        streams = [[]] # stacked lists of events of the "compiled" template
         dirmap = {} # temporary mapping of directives to elements
         ns_prefix = {}
         depth = 0
-        in_fallback = False
-        fallback_stream = None
+        in_fallback = 0
         include_href = None
 
         if not isinstance(source, Stream):
@@ -78,6 +77,7 @@
                                encoding=encoding)
 
         for kind, data, pos in source:
+            stream = streams[-1]
 
             if kind is START_NS:
                 # Strip out the namespace declaration for template directives
@@ -138,9 +138,9 @@
                         if not include_href:
                             raise TemplateSyntaxError('Include misses required '
                                                       'attribute "href"', *pos)
+                        streams.append([])
                     elif tag.localname == 'fallback':
-                        in_fallback = True
-                        fallback_stream = []
+                        in_fallback += 1
 
                 else:
                     stream.append((kind, (tag, new_attrs), pos))
@@ -150,13 +150,12 @@
             elif kind is END:
                 depth -= 1
 
-                if in_fallback:
-                    if data == self.XINCLUDE_NAMESPACE['fallback']:
-                        in_fallback = False
-                    else:
-                        fallback_stream.append((kind, data, pos))
+                if in_fallback and data == self.XINCLUDE_NAMESPACE['fallback']:
+                    in_fallback -= 1
                 elif data == self.XINCLUDE_NAMESPACE['include']:
-                    stream.append((INCLUDE, (include_href, fallback_stream), pos))
+                    fallback = streams.pop()
+                    stream = streams[-1]
+                    stream.append((INCLUDE, (include_href, fallback), pos))
                 else:
                     stream.append((kind, data, pos))
 
@@ -182,7 +181,14 @@
             else:
                 stream.append((kind, data, pos))
 
-        return stream
+        assert len(streams) == 1
+        return streams[0]
+
+    def _prepare(self, stream):
+        for kind, data, pos in Template._prepare(self, stream):
+            if kind is INCLUDE:
+                data = data[0], list(self._prepare(data[1]))
+            yield kind, data, pos
 
     def _include(self, stream, ctxt):
         """Internal stream filter that performs inclusion of external
@@ -204,6 +210,8 @@
                 except TemplateNotFound:
                     if fallback is None:
                         raise
+                    for filter_ in self.filters:
+                        fallback = filter_(iter(fallback), ctxt)
                     for event in fallback:
                         yield event
             else:
Copyright (C) 2012-2017 Edgewall Software