Search Reference
This narrative covers all the possible ways to search for elements
when using Twiddler.
We'll demonstrate this using the following example:
>>> from twiddler import Twiddler
>>> t = Twiddler('''<html>
... <body>
... <div id="one" name="aname">
... <div id="subone" name="subone"/>
... <div id="subtwo" name="subtwo"/>
... </div>
... <div id="two" name="aname">
... <div id="subone" name="subone"/>
... <div id="subtwo" name="subtwo"/>
... </div>
... </body>
... </html>''')
As we've already seen, Twiddlers allow elements to be looked up
using python's item access syntax:
>>> t['aname'].replace(name='name2')
By default, elements can be looked up by either their 'name' or
their 'id' attributes:
>>> t['one'].replace(name='name1')
TwiddlerElements can also be searched in the same way, but the
search will be limited to the contents of the TwiddlerElement:
>>> t['one']['subone'].replace('one')
>>> t['one']['subtwo'].replace('two')
>>> t['two']['subone'].replace('three')
>>> t['two']['subtwo'].replace('four')
We can see the results of all this by rendering the Twiddler:
>>> print t.render()
<html>
<body>
<div id="one" name="name1">
<div id="subone" name="subone">one</div>
<div id="subtwo" name="subtwo">two</div>
</div>
<div id="two" name="name2">
<div id="subone" name="subone">three</div>
<div id="subtwo" name="subtwo">four</div>
</div>
</body>
</html>
Beware, however, that when you change a Twiddler, the promise that
the "last" element will always be returned will probably not be
met in the way you expect:
>>> t['one'].replace(name='name2')
>>> t['name2'].replace('Oops!')
>>> print t.render()
<html>
<body>
<div id="one" name="name2">Oops!</div>
<div id="two" name="name2">
<div id="subone" name="subone">three</div>
<div id="subtwo" name="subtwo">four</div>
</div>
</body>
</html>
This is an artifact of trying to keep Twiddlers as quick as
possible. You can avoid this by using more unique identifiers.
You may be wondering what happens if two different nodes share an
id and a name:
>>> t = Twiddler('''<tag>
... <taga name="something"/>
... <tagb id="something"/>
... </tag>''')
The answer, for the default setup of a Twiddler, is that the
element with a matching id will be found instead of the element
with a matching name:
>>> t['something'].replace('found!')
>>> print t.render()
<tag>
<taga name="something" />
<tagb id="something">found!</tagb>
</tag>
If you need to be specific about which attribute you'd like to
match, both Twiddler and TwiddlerElement instances have a 'getBy'
method that will let you search more specifically:
>>> t.getBy(name='something').replace('found by name')
>>> t.getBy(id='something').replace('found by id')
>>> print t.render()
<tag>
<taga name="something">found by name</taga>
<tagb id="something">found by id</tagb>
</tag>
Now, you may be generating XML or some other flavour of tagged
language where you want to search by something other than the 'id'
or 'name' attributes. In this case, you can tell the Twiddler what
attributes to index when you construct it:
>>> t = Twiddler('''<tag>
... <taga x="something"/>
... <tagb y="something"/>
... </tag>''',
... indexes=('x','y'))
The order in which the indexes are specified is the order in which
they will be searched:
>>> t['something'].replace('found!')
>>> print t.render()
<tag>
<taga x="something">found!</taga>
<tagb y="something" />
</tag>
But, as you'd expect, you can use the 'getBy' method to search
more specifically:
>>> t.getBy(x='something').replace('found by x')
>>> t.getBy(y='something').replace('found by y')
>>> print t.render()
<tag>
<taga x="something">found by x</taga>
<tagb y="something">found by y</tagb>
</tag>
changed November 15, 2007