DIV.elements(replace=...), thanks Anthony

This commit is contained in:
mdipierro
2012-08-24 22:17:49 -05:00
parent a3df5c465e
commit 1d56e253d7
3 changed files with 84 additions and 30 deletions
+1
View File
@@ -76,6 +76,7 @@
### Other Improvements
- DIV(..).elements(...replace=...), thanks Anthony
- new layout based on Twitter Bootstrap
- New generic views: generic.ics (Mac Mail Calendar) and generic.map (Google Maps)
- request.args(0,default=0, cast=int, otherwise=URL(...)), thanks Anthony
+1 -1
View File
@@ -1 +1 @@
Version 2.00.0 (2012-08-24 19:24:54) dev
Version 2.00.0 (2012-08-24 22:17:44) dev
+82 -29
View File
@@ -962,6 +962,48 @@ class DIV(XmlComponent):
>>> for c in a.elements('input, select, textarea'): c['_disabled'] = 'disabled'
>>> a.xml()
'<form action="" enctype="multipart/form-data" method="post"><input disabled="disabled" type="text" /><select disabled="disabled"><option value="0">0</option></select><textarea cols="40" disabled="disabled" rows="10"></textarea></form>'
Elements that are matched can also be replaced or removed by specifying
a "replace" argument (note, a list of the original matching elements
is still returned as usual).
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
>>> b = a.elements('span.abc', replace=P('x', _class='xyz'))
>>> print a
<div><div><p class="xyz">x</p><div><p class="xyz">x</p><p class="xyz">x</p></div></div></div>
"replace" can be a callable, which will be passed the original element and
should return a new element to replace it.
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
>>> b = a.elements('span.abc', replace=lambda el: P(el[0], _class='xyz'))
>>> print a
<div><div><p class="xyz">x</p><div><p class="xyz">y</p><p class="xyz">z</p></div></div></div>
If replace=None, matching elements will be removed completely.
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
>>> b = a.elements('span', find='y', replace=None)
>>> print a
<div><div><span class="abc">x</span><div><span class="abc">z</span></div></div></div>
If a "find_text" argument is specified, elements will be searched for text
components that match find_text, and any matching text components will be
replaced (find_text is ignored if "replace" is not also specified).
Like the "find" argument, "find_text" can be a string or a compiled regex.
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
>>> b = a.elements(find_text=re.compile('x|y|z'), replace='hello')
>>> print a
<div><div><span class="abc">hello</span><div><span class="abc">hello</span><span class="abc">hello</span></div></div></div>
If other attributes are specified along with find_text, then only components
that match the specified attributes will be searched for find_text.
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='efg'), SPAN('z', _class='abc'))))
>>> b = a.elements('span.efg', find_text=re.compile('x|y|z'), replace='hello')
>>> print a
<div><div><span class="abc">x</span><div><span class="efg">hello</span><span class="abc">z</span></div></div></div>
"""
if len(args)==1:
args = [a.strip() for a in args[0].split(',')]
@@ -990,49 +1032,60 @@ class DIV(XmlComponent):
return self.elements(*args,**kargs)
# make a copy of the components
matches = []
first_only = False
if kargs.has_key("first_only"):
first_only = kargs["first_only"]
del kargs["first_only"]
# check if the component has an attribute with the same
# value as provided
check = True
tag = getattr(self,'tag').replace("/","")
tag = getattr(self,'tag').replace('/', '')
if args and tag not in args:
check = False
for (key, value) in kargs.items():
if isinstance(value,(str,int)):
if self[key] != str(value):
if key not in ['first_only', 'replace', 'find_text']:
if isinstance(value, (str, int)):
if self[key] != str(value):
check = False
elif key in self.attributes:
if not value.search(str(self[key])):
check = False
else:
check = False
elif key in self.attributes:
if not value.search(str(self[key])):
check = False
else:
check = False
if 'find' in kargs:
find = kargs['find']
is_regex = not isinstance(find, (str, int))
for c in self.components:
if isinstance(find,(str,int)):
if isinstance(c,str) and str(find) in c:
check = True
else:
if isinstance(c,str) and find.search(c):
check = True
if (isinstance(c, str) and ((is_regex and find.search(c)) or
(str(find) in c))):
check = True
# if found, return the component
if check:
matches.append(self)
if first_only:
return matches
# loop the copy
for c in self.components:
if isinstance(c, XmlComponent):
kargs['first_only'] = first_only
child_matches = c.elements( *args, **kargs )
if first_only and len(child_matches) != 0:
return child_matches
matches.extend( child_matches )
return matches
first_only = kargs.get('first_only', False)
replace = kargs.get('replace', False)
find_text = replace is not False and kargs.get('find_text', False)
is_regex = not isinstance(find_text, (str, int, bool))
find_components = not (check and first_only)
def replace_component(i):
if replace is None:
del self[i]
elif callable(replace):
self[i] = replace(self[i])
else:
self[i] = replace
# loop the components
if find_text or find_components:
for i, c in enumerate(self.components):
if check and find_text and isinstance(c, str) and \
((is_regex and find_text.search(c)) or (str(find_text) in c)):
replace_component(i)
if find_components and isinstance(c, XmlComponent):
child_matches = c.elements(*args, **kargs)
if len(child_matches):
if not find_text and replace is not False and child_matches[0] is c:
replace_component(i)
if first_only:
return child_matches
matches.extend(child_matches)
return matches
def element(self, *args, **kargs):
"""