Node Tree Navigation¶
It’s often much more practical to modify child nodes directly instead of
giving each its own render_name
method. Conveniently you can
access child nodes of a node directly as attribute using the child
node’s name:
from tdi import html
template = html.from_string("""
<html>
<body>
<ul class="menu" tdi="menu">
<li><a href="menu1" tdi="menu1">some menu item</a></li>
<li><a href="menu2" tdi="menu2">Editing Content & Attributes</a></li>
<li><a href="menu3" tdi="menu3">Other menu item</a></li>
</ul>
</body>
</html>
""")
class Model(object):
def __init__(self, page):
self._page = page
def render_menu(self, node):
if self._page == 1:
node.menu1.hiddenelement = True
elif self._page == 2:
node.menu2.hiddenelement = True
elif self._page == 3:
node.menu3.hiddenelement = True
model = Model(page=2)
template.render(model)
However, since the node object defines some names by itself, you cannot address every name by this method [1]. Thatswhy there’s a canonical (but more ugly) method, too, which takes a string as the child node’s name. This method is also reasonable to use if you don’t know the node name in advance (same template as above, just a different model):
class Model(object):
def __init__(self, page):
self._page = page
def render_menu(self, node):
node("menu%d" % self._page).hiddenelement = True
The output is the same for both cases:
<html>
<body>
<ul class="menu">
<li><a href="menu1">some menu item</a></li>
<li>Editing Content & Attributes</li>
<li><a href="menu3">Other menu item</a></li>
</ul>
</body>
</html>
Avoiding Model Calls¶
Directly accessed child nodes implicitely create another need – to
not handle nodes twice (because a render_name
method might be
called for those nodes as well). You have three options here:
Don’t define
render_name
methods for those nodes. This may lead to strange effects if later such a method is created nevertheless (really strange if the creator just added a new node with the same name in a completely different context in ignorance of the old usage).Returning a true value from a render method marks the current node and all of its children as done. No methods are called for this subtree anymore.
from tdi import html template = html.from_string(""" <html> <body> <ul class="menu" tdi="menu"> <li><a href="menu1" tdi="menu1">some menu item</a></li> <li><a href="menu2" tdi="menu2">Editing Content & Attributes</a></li> <li><a href="menu3" tdi="menu3">Other menu item</a></li> </ul> </body> </html> """) class Model(object): def __init__(self, page): self._page = page def render_menu(self, node): node("menu%d" % self._page).hiddenelement = True return True # avoid calling methods for subnodes def render_menu1(self, node): node.content = "shouldn't come here..." model = Model(page=2) template.render(model)
You can flag particular nodes for no automatic method calling in the template already with the
*
flag.<html> <body> <ul class="menu" tdi="menu"> <li><a href="menu1" tdi="*menu1">some menu item</a></li> <li><a href="menu2" tdi="*menu2">Editing Content & Attributes</a></li> <li><a href="menu3" tdi="*menu3">Other menu item</a></li> </ul> </body> </html>
The result is the same, of course:
<html>
<body>
<ul class="menu">
<li><a href="menu1">some menu item</a></li>
<li>Editing Content & Attributes</li>
<li><a href="menu3">Other menu item</a></li>
</ul>
</body>
</html>
Inspecting Templates¶
If you’re unsure about the structure of your template (especially after combining different templates or prerendering), you can ask TDI for it.
The → tree
attribute of the template object
holds the node tree. It can be visualized using the
→ to_string()
method:
from tdi import html
template = html.from_string("""
<html>
<body>
<h1 tdi="doctitle">doc title goes here</h1>
<p tdi="intro">Intro goes <span tdi="where">here</span>.</p>
</body>
</html>
""")
print template.tree.to_string()
This script produces a simple nested node name output:
/
doctitle
intro
where
\
This output is useful for debugging purposes. It can also be used for simple automated tests if and how the node structure changed after modifications of a template, as well.
to_string()
can also be more verbose:
print template.tree.to_string(verbose=True)
The verbose output gives more node information (if there is some, which is not the case here) and shortened versions of the text between the nodes. That way it’s easily possible to check if the template was parsed correctly (i.e. according to your expectations):
/
'\n<html>\n<body>\n '
doctitle
'doc title goes here'
'\n '
intro
'Intro goes '
where
'here'
'.'
'\n</body>\n</html>\n'
\
For your convenience the the to_string()
method is connected to
the string representations of the template object (nodes only) and the
tree
attribute (verbose variant), so you can just write:
print template
in order to get a quick abstract of the template.
[1] | The following attributes are owned by the node object:
content , copy , ctx ,
hiddenelement , closedelement , iterate ,
raw , remove , render , repeat ,
replace . Python keywords cannot be used either, because
attribute access of a python keyword raises a SyntaxError. |