changeset 771:2c2e9e685424 trunk

Unbuffered match templates could result in parts of the matched content being included in the output if the match template didn't actually consume it via one or more calls to the `select()` function. Closes #243. Thanks to Felix Schwarz for the report and test case.
author cmlenz
date Mon, 07 Jul 2008 16:35:06 +0000
parents 3a59144a35b1
children e01c9ad52f09
files ChangeLog genshi/template/markup.py genshi/template/plugin.py genshi/template/tests/markup.py
diffstat 4 files changed, 38 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -20,6 +20,9 @@
  * Includes from templates loaded via an absolute path now include the correct
    file in nested directories as long if no search path has been configured
    (ticket #240).
+ * Unbuffered match templates could result in parts of the matched content
+   being included in the output if the match template didn't actually consume
+   it via one or more calls to the `select()` function (ticket #243).
 
 
 Version 0.5
--- a/genshi/template/markup.py
+++ b/genshi/template/markup.py
@@ -278,13 +278,11 @@
                     if 'not_buffered' not in hints:
                         content = list(content)
 
-                    if tail:
-                        for test in [mt[0] for mt in match_templates]:
-                            test(tail[0], namespaces, ctxt, updateonly=True)
-
                     # Make the select() function available in the body of the
                     # match template
+                    selected = [False]
                     def select(path):
+                        selected[0] = True
                         return Stream(content).select(path, namespaces, ctxt)
                     vars = dict(select=select)
 
@@ -300,6 +298,19 @@
                             ctxt, start=idx + 1, **vars):
                         yield event
 
+                    # If the match template did not actually call select to
+                    # consume the matched stream, the original events need to
+                    # be consumed here or they'll get appended to the output
+                    if not selected[0]:
+                        for event in content:
+                            pass
+
+                    # Let the remaining match templates know about the last
+                    # event in the matched content, so they can update their
+                    # internal state accordingly
+                    for test in [mt[0] for mt in match_templates]:
+                        test(tail[0], namespaces, ctxt, updateonly=True)
+
                     break
 
             else: # no matches
--- a/genshi/template/plugin.py
+++ b/genshi/template/plugin.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2006-2007 Edgewall Software
+# Copyright (C) 2006-2008 Edgewall Software
 # Copyright (C) 2006 Matthew Good
 # All rights reserved.
 #
--- a/genshi/template/tests/markup.py
+++ b/genshi/template/tests/markup.py
@@ -708,6 +708,25 @@
             </body>
         </html>""", tmpl.generate().render())
 
+    def test_match_without_select(self):
+        # See <http://genshi.edgewall.org/ticket/243>
+        xml = ("""<html xmlns:py="http://genshi.edgewall.org/">
+          <py:match path="body" buffer="false">
+            <body>
+              This replaces the other text.
+            </body>
+          </py:match>
+          <body>
+            This gets replaced.
+          </body>
+        </html>""")
+        tmpl = MarkupTemplate(xml, filename='test.html')
+        self.assertEqual("""<html>
+            <body>
+              This replaces the other text.
+            </body>
+        </html>""", tmpl.generate().render())
+
 
 def suite():
     suite = unittest.TestSuite()
Copyright (C) 2012-2017 Edgewall Software