Ian Bicking wrote:
I'm surprised this has never come up for me before, but now I want to render a recursive data structure and I'm at a loss how I might do that in ZPT. Or, what the best workaround would be. E.g.:
['a', 'b', ['c', ['d', 'e']]]
Becomes:
<ul> <li>a</li> <li>b</li> <ul> <li>c</li> <ul> <li>d</li> <li>e</li> </ul> </ul> </ul>
I guess the template could call itself repeatedly. Which means the list can't be embedded in any other markup. Hrm... in Cheetah I'd do:
#def make_list(items) <ul> #for item in items #if isinstance(item, list) $make_list(item) #else <li>$item</li> #end if #end for </ul> #end def $make_list(items)
It's a code-heavy template, and maybe it should just be written in Python, but it's also reasonable to allow people to add classes to items, further logic, etc.
I think it should *definitely* be written in Python, although a "Script (Python)" should suffice. Add a "Script (Python)" with an ID of "make_list" and a parameter list of "items" The following is untested, but should work, I think. Beware of any special text in the strings (&,<,>,etc). ###### text = "<ul>\n" for item in items: if isinstance( item, ( list, tuple )): text += context.make_list( item ) else: text += "<li>" + str(item) + "</li>\n" return text + "</ul>" ############
Nikko Wolf schrieb:
Ian Bicking wrote:
I'm surprised this has never come up for me before, but now I want to render a recursive data structure and I'm at a loss how I might do that in ZPT. Or, what the best workaround would be. E.g.:
['a', 'b', ['c', ['d', 'e']]]
Becomes:
<ul> <li>a</li> <li>b</li> <ul> <li>c</li> <ul> <li>d</li> <li>e</li> </ul> </ul> </ul>
The code above is not valid HTML[1]. This is one way how to do it: <ul tal:define="nodes python:['a', 'b', ['c', ['d', 'e']]]"> <li metal:define-macro="item" tal:repeat="node nodes"> <span tal:define="global is_list python:same_type([], node); content python:is_list and 'list:' or node" tal:replace="content"/> <ul tal:condition="is_list" tal:define="nodes node"> <li metal:use-macro="template/macros/item"/> </ul> </li> </ul>
I guess the template could call itself repeatedly. Which means the list can't be embedded in any other markup.
To embed it in another template simply call it: <ul tal:replace="structure here/list"/> (Or define a macro and use that). Even better if the logic is in a script that renders the template, I think. Tonico [1] <ul> can not have <ul> as parent http://zvon.org/xxl/xhtmlReference/Output/Strict/el_ul.html
Nikko Wolf wrote:
Ian Bicking wrote:
I'm surprised this has never come up for me before, but now I want to render a recursive data structure and I'm at a loss how I might do that in ZPT. Or, what the best workaround would be. E.g.:
['a', 'b', ['c', ['d', 'e']]]
Becomes:
<ul> <li>a</li> <li>b</li> <ul> <li>c</li> <ul> <li>d</li> <li>e</li> </ul> </ul> </ul>
I've made recursive macros before. It's not so different from other recursion techniques. Here's one to render a site tree:: <html> <head> <title tal:content="template/title">The title</title> </head> <body> Site structure: <tal:contain define="location nocall:here"> <div metal:use-macro="template/macros/list" /> </tal:contain> </body> </html> <tal:hidemacro replace="nothing"> <metal:recurse define-macro="list"> <ul> <li tal:repeat="elt location/objectValues"> <span tal:content="elt/getId">objectId</span> <metal:block tal:condition="elt/isPrincipiaFolderish" tal:define="location nocall:elt"> <div metal:use-macro="template/macros/list" /> </metal:recurse> </li> </ul> </metal:recurse> </tal:hidemacro> It will go from 'context', of course, unless you were to change the definition of 'location' in the page. You can imagine how this would work with a nested list: you just have to have ways of checking containership and getting contents. --jcc -- "Building Websites with Plone" http://plonebook.packtpub.com/ Enfold Systems, LLC http://www.enfoldsystems.com
participants (3)
-
J Cameron Cooper -
Nikko Wolf -
Tonico Strasser