changeset 694:07e3f6f0ef57 trunk

Match templates are now applied in a more controlled fashion: in the order they are declared in the template source, all match templates up to (and including) the matching template itself are applied to the matched content, whereas the match templates declared after the matching template are only applied to the generated content. Fixes #186. Many thanks to Matt Chaput for reporting the problem and providing a test case.
author cmlenz
date Wed, 26 Mar 2008 22:10:36 +0000
parents 35e143388705
children ed5044d318ed
files ChangeLog doc/upgrade.txt doc/xml-templates.txt genshi/template/markup.py genshi/template/tests/directives.py
diffstat 5 files changed, 54 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -51,6 +51,11 @@
    output, instead of building a big string and returning it.
  * The XHTML serializer now strips `xml:space` attributes as they are only
    allowed on very few tags.
+ * Match templates are now applied in a more controlled fashion: in the order
+   they are declared in the template source, all match templates up to (and
+   including) the matching template itself are applied to the matched content,
+   whereas the match templates declared after the matching template are only
+   applied to the generated content (ticket #186).
 
 
 Version 0.4.4
--- a/doc/upgrade.txt
+++ b/doc/upgrade.txt
@@ -30,6 +30,18 @@
 warned that lenient error handling may be removed completely in a
 future release.
 
+There has also been a subtle change to how ``py:match`` templates are
+processed: in previous versions, all match templates would be applied
+to the content generated by the matching template, and only the
+matching template itself was applied recursively to the original
+content. This behavior resulted in problems with many kinds of
+recursive matching, and hence was changed for 0.5: now, all match
+templates declared before the matching template are applied to the
+original content, and match templates declared after the matching
+template are applied to the generated content. This change should not
+have any effect on most applications, but you may want to check your
+use of match templates to make sure.
+
 
 Upgrading from Genshi 0.3.x to 0.4.x
 ------------------------------------
--- a/doc/xml-templates.txt
+++ b/doc/xml-templates.txt
@@ -322,6 +322,12 @@
 
 .. _`Using XPath`: streams.html#using-xpath
 
+Match templates are applied both to the original markup as well to the
+generated markup. The order in which they are applied depends on the order
+they are declared in the template source: a match template defined after
+another match template is applied to the output generated by the first match
+template. The match templates basically form a pipeline.
+
 This directive can also be used as an element:
 
 .. code-block:: genshi
--- a/genshi/template/markup.py
+++ b/genshi/template/markup.py
@@ -272,9 +272,10 @@
                     # Consume and store all events until an end event
                     # corresponding to this start event is encountered
                     inner = _strip(stream)
-                    if 'match_once' not in hints \
-                            and 'not_recursive' not in hints:
-                        inner = self._match(inner, ctxt, [match_templates[idx]])
+                    pre_match_templates = match_templates[:idx + 1]
+                    if 'match_once' not in hints and 'not_recursive' in hints:
+                        pre_match_templates.pop()
+                    inner = self._match(inner, ctxt, pre_match_templates)
                     content = list(self._include(chain([event], inner, tail),
                                                  ctxt))
 
@@ -290,11 +291,9 @@
                     # Recursively process the output
                     template = _apply_directives(template, ctxt, directives)
                     remaining = match_templates
-                    if 'match_once' not in hints:
-                        remaining = remaining[:idx] + remaining[idx + 1:]
                     for event in self._match(self._exec(
                                     self._eval(self._flatten(template, ctxt),
-                                    ctxt), ctxt), ctxt, remaining):
+                                    ctxt), ctxt), ctxt, match_templates[idx + 1:]):
                         yield event
 
                     ctxt.pop()
--- a/genshi/template/tests/directives.py
+++ b/genshi/template/tests/directives.py
@@ -631,6 +631,32 @@
           </body>
         </html>""", str(tmpl.generate()))
 
+    def test_recursive_match_3(self):
+        tmpl = MarkupTemplate("""<test xmlns:py="http://genshi.edgewall.org/">
+          <py:match path="b[@type='bullet']">
+            <bullet>${select('*|text()')}</bullet>
+          </py:match>
+          <py:match path="group[@type='bullet']">
+            <ul>${select('*')}</ul>
+          </py:match>
+          <py:match path="b">
+            <generic>${select('*|text()')}</generic>
+          </py:match>
+
+          <b>
+            <group type="bullet">
+              <b type="bullet">1</b>
+              <b type="bullet">2</b>
+            </group>
+          </b>
+        </test>
+        """)
+        self.assertEqual("""<test>
+            <generic>
+            <ul><bullet>1</bullet><bullet>2</bullet></ul>
+          </generic>
+        </test>""", str(tmpl.generate()))
+
     def test_not_match_self(self):
         """
         See http://genshi.edgewall.org/ticket/77
Copyright (C) 2012-2017 Edgewall Software