htmlzopetemplate-talzpttemplate-metal

Zope (ZPT) overlapping tags


I try to create an open div tag condition and close a div tag in another condition with TAL in a Zope Page Template but I'm not allowed to overlap tags.

Here is my code :

<div id="notaccordion">                                                                                      
    <tal:x repeat="item python:range(26)">                                                                                                                         
        <tal:x define="global block_name python:current.values()[0]['block_name']">         

            <tal:x condition="python:isDone">                                                                               
                </div>                                                                                  
            </tal:x>    

            <tal:x condition="python:not isDone">                                                                                     
                <tal:x replace="python:block_name">                                                                                                                                             
                </tal:x>                                                                                                       
                <div>                                                                                                                                                                                                                                                                                                                                         
            </tal:x>  

        </tal:x>                                                                     
     </tal:x>                                                                                                                              
 </div> 

The important part is:

            <tal:x condition="python:isDone">                                                                               
                </div>                                                                                  
            </tal:x>

And here is the error.

Compilation failed
zope.tal.taldefs.TALError: TAL attributes on <tal:x> require explicit </tal:x>

I tried with a Python script but it didn't work either.

<div id="notaccordion">                                                                                      
    <tal:x repeat="item python:range(26)">                                                                                                                         
        <tal:x define="global block_name python:current.values()[0]['block_name']">         

            <tal:x condition="python:isDone">                                                                               
                <tal:x content="python:context[close_div]()">
                </tal:x>                                                                                           
            </tal:x>    

            <tal:x condition="python:not isDone">
                <tal:x replace="python:block_name">                                                                                                                                                         
                </tal:x>                                                                                                       
                <tal:x content="python:context[open_div]()">
                </tal:x>                                                                                                                                                                                                                                                                                                                                                
            </tal:x>  

        </tal:x>                                                                     
    </tal:x>                                                                                                                              
</div> 

With close_div script:

print '</div>'
return printed

It returns &lt;/div&gt; instead of </div>

If you wonder why I'm doing it. I have a tree structure that I need to display. Since I (think I) can't do it recursively, I try to emulate it using a LIFO list. And current is my current node.

I try to achieve this (node is dict of dict... used as a tree) :

lifo = list()
lifo.append([node, False])

while lifo:
    current, isDone = lifo[-1]
    block = current.keys()[0]
    if isDone:
        print '</div>'
        lifo.pop()
    else:
        lifo[-1][1] = True
        print '<div>'
        print block
        children = current[block].get('children', {})
        if children:
            for childBlock, childValue in children.items():
                lifo.append([{childBlock:childValue}, False])

Any help or suggestion is appreciated


Solution

  • Page templates have to be valid XML, so you cannot just arbitrarily include tags willy nilly. Tree structures are best handled recursively (perhaps with macro snippets):

    <metal:recurse define-macro="list">
      <ul>
        <li tal:repeat="el elements">
          <span tal:content="el/id">element id</span>
          <metal:block tal:condition="el/children"
                       tal:define="elements el/children">
            <div metal:use-macro="template/macros/list" />
          </metal:recurse>
        </li>
      </ul>
    </metal:recurse>
    

    The Plone navigation portlet, for example, also uses a separate macro template for each level, calling into itself to render children (recurse is the same template).

    For your specific method using a open_div or close_div script, you need to mark the content value as structure to prevent the automatic HTML escaping from taking place:

    <tal:x content="structure python:context[open_div]()">