Updated ElementBase._setSubText and added unit tests.

_setSubText can now handle elements specified by an XPath expression, and
will build up the element tree as needed, reusing an existing elements in
the path.
This commit is contained in:
Lance Stout 2010-08-24 09:37:42 -04:00
parent 203986dd7c
commit c8f406d1b3
2 changed files with 94 additions and 12 deletions

View file

@ -374,6 +374,49 @@ class ElementBase(object):
else: else:
return stanza.text return stanza.text
def _setSubText(self, name, text=None, keep=False):
"""
Set the text contents of a sub element.
In case the element does not exist, a element will be created,
and its text contents will be set.
If the text is set to an empty string, or None, then the
element will be removed, unless keep is set to True.
Arguments:
name -- The name or XPath expression of the element.
text -- The new textual content of the element. If the text
is an empty string or None, the element will be removed
unless the parameter keep is True.
keep -- Indicates if the element should be kept if its text is
removed. Defaults to False.
"""
name = self._fix_ns(name)
element = self.xml.find(name)
if not text and not keep:
return self.__delitem__(name)
if element is None:
# We need to add the element. If the provided name was
# an XPath expression, some of the intermediate elements
# may already exist. If so, we want to use those instead
# of generating new elements.
last_xml = self.xml
walked = []
for ename in name.split('/'):
walked.append(ename)
element = self.xml.find("/".join(walked))
if element is None:
element = ET.Element(ename)
last_xml.append(element)
last_xml = element
element = last_xml
element.text = text
return element
@property @property
def attrib(self): #backwards compatibility def attrib(self): #backwards compatibility
return self return self
@ -469,18 +512,6 @@ class ElementBase(object):
return False return False
return True return True
def _setSubText(self, name, attrib={}, text=None):
if '}' not in name:
name = "{%s}%s" % (self.namespace, name)
if text is None or text == '':
return self.__delitem__(name)
stanza = self.xml.find(name)
if stanza is None:
stanza = ET.Element(name)
self.xml.append(stanza)
stanza.text = text
return stanza
def _delSub(self, name): def _delSub(self, name):
if '}' not in name: if '}' not in name:
name = "{%s}%s" % (self.namespace, name) name = "{%s}%s" % (self.namespace, name)

View file

@ -301,5 +301,56 @@ class TestElementBase(SleekTest):
self.failUnless(stanza['bar'] == 'found', self.failUnless(stanza['bar'] == 'found',
"_getSubText value incorrect: %s." % stanza['bar']) "_getSubText value incorrect: %s." % stanza['bar'])
def testSubElement(self):
"""Test setting the contents of a sub element."""
class TestStanza(ElementBase):
name = "foo"
namespace = "foo"
interfaces = set(('bar', 'baz'))
def setBaz(self, value):
self._setSubText("wrapper/baz", text=value)
def getBaz(self):
return self._getSubText("wrapper/baz")
def setBar(self, value):
self._setSubText("wrapper/bar", text=value)
def getBar(self):
return self._getSubText("wrapper/bar")
stanza = TestStanza()
stanza['bar'] = 'a'
stanza['baz'] = 'b'
self.checkStanza(TestStanza, stanza, """
<foo xmlns="foo">
<wrapper>
<bar>a</bar>
<baz>b</baz>
</wrapper>
</foo>
""")
stanza._setSubText('bar', text='', keep=True)
self.checkStanza(TestStanza, stanza, """
<foo xmlns="foo">
<wrapper>
<bar />
<baz>b</baz>
</wrapper>
</foo>
""", use_values=False)
stanza['bar'] = 'a'
stanza._setSubText('bar', text='')
self.checkStanza(TestStanza, stanza, """
<foo xmlns="foo">
<wrapper>
<baz>b</baz>
</wrapper>
</foo>
""")
suite = unittest.TestLoader().loadTestsFromTestCase(TestElementBase) suite = unittest.TestLoader().loadTestsFromTestCase(TestElementBase)