from xml.etree import cElementTree
import re
#Compatibility with 3.0
try:
#3.x
import io
def is_file(ob):
return isinstance(ob, io.IOBase)
def is_text(ob):
return type(ob) == str
except:
#2.x
def is_file(ob):
return isinstance(ob, file)
def is_text(ob):
return isinstance(ob, basestring)
def attr_str(obj):
return ' '.join('%s = "%s"' % (key,value) for key,value in obj.items())
def text(obj):
if type(obj) in (int,float):
return str(obj)
elif is_text(obj):
return obj
return str(obj)
PREFIX_PAT = re.compile('(\{.*\})')
class xml(object):
"""
Usage:
xml(tag, child, ..., attr = value, ...)
returns new element with specified child elements and attributes
xml(tag, text, child, ..., attr = value, ...)
returns new element with specified text, child elements, and attributes
xml(literal)
returns new element for literal xml string
xml(xmlable)
returns xmlable.__xml__()
Example:
from xmlwrapper import xml
table_elt = xml('table', xml('tr',xml('td',"header",colspan = "2")),
xml('tr',xml('td',xml('b',"bold text")),
xml('td',"plain text")))
table_elt['border'] = "1"
open("test.html","w").write(str(xml('html',xml('body',table_elt))))
print table_elt.navlist('tr')
Example of __xml__ interface:
class xmldict(dict):
def __xml__(self):
xml_elt = xml('dict')
for key in self:
xml_elt.append(xml('dictent',xml('key',str(key)),
xml('value',str(self[key]))))
return xml_elt
e = xmldict()
e['foo'] = 'bar'
print xml(e)
"""
def __new__(cls,tag,thing = None,*args,**kwargs):
if hasattr(tag,'__xml__'):
return tag.__xml__()
self = object.__new__(xml)
if cElementTree.iselement(tag):
self.__content = tag
elif isinstance(tag,cElementTree.ElementTree):
self.__content = tag.getroot()
elif is_file(tag):
self.__content = cElementTree.parse(tag).getroot()
elif isinstance(tag,str) and len(tag) > 0 and tag[0] == '<':
self.__content = cElementTree.fromstring(tag)
else:
if type(tag) != str:
raise TypeError("Cannot convert %s object to xml" % str(type(tag)))
self.__content = cElementTree.fromstring('<%s/>' % tag)
if is_text(thing) or type(thing) == int:
self.__content.text = text(thing)
elif thing != None:
self.append(xml(thing))
for subthing in args:
self.append(xml(subthing))
for key,value in kwargs.items():
if key == '__class' or key == 'klass':
self['class'] = value
else:
self[key] = value
if '{' in self.__content.tag:
self.__prefix = PREFIX_PAT.search(self.__content.tag).groups()[0]
else:
self.__prefix = ''
return self
def clear(self):
self.__content.clear()
def append(self,xml_obj):
assert type(xml_obj) == xml
self.__content.append(xml_obj.__content)
def setprefix(self, prefix):
self.__prefix = prefix
def getprefix(self):
return self.__prefix
def remove(self,xml_obj):
assert type(xml_obj) == xml
self.__content.remove(xml_obj.__content)
def __xml__(self):
return self
def __str__(self):
return cElementTree.tostring(self.__content)
def __repr__(self):
return str(self)
def __getitem__(self,attr):
qattr = self.__prefix + attr
if qattr in self.__content.keys():
return self.__content.get(qattr)
raise AttributeError("<%s> element does not have attribute %s" % (self.tag, attr))
def get(self,attr, default):
return self.__content.get(self.__prefix + attr, default)
def __setitem__(self,attr,value):
assert type(attr) == str and type(value) == str
self.__content.set(attr,value)
def getxml(self):
return self.__content
def __get_text(self):
if self.__content.text:
return self.__content.text
return ''
def __set_text(self, value):
if not is_text(value):
raise ValueError("xmlwrapper: cannot set text of element to object of type %s" % str(type(value)))
self.__content.text = value
text = property(__get_text,__set_text)
def __get_tag(self):
return self.__strip_key(self.__content.tag)
def __set_tag(self,tag_value):
assert type(tag_value) == str
self.__content.tag = self.__prefix + tag_value
tag = property(__get_tag,__set_tag)
def pretty_list(self):
str_list = []
for child_elt in self.__content.getchildren():
for pretty_str in xml(child_elt).pretty_list():
str_list.append(pretty_str)
str_list = [" " + pretty_str for pretty_str in str_list]
head_str = ' '.join(str_item for str_item in [self.tag, attr_str(self.__content.attrib)] if str_item.strip())
if str_list:
str_list = ["<%s>" % head_str, self.text] + str_list + ["%s>" % self.tag]
elif self.text:
str_list = ["<%s>%s%s>" % (head_str, self.text, self.tag)]
else:
str_list = ["<%s/>" % head_str]
return str_list
def pretty(self):
return '\n'.join(pretty_str for pretty_str in self.pretty_list() if pretty_str.strip())
def __strip_key(self,key):
return key[len(self.__prefix):]
def keys(self):
return [self.__strip_key(key) for key in self.__content.keys()]
def attrs(self):
return self.keys()
def items(self):
return [(self.__strip_key(k),v) for k,v in self.__content.items()]
def iterattrs(self):
return self.__content.attrib.iterkeys()
def iterelts(self):
return iter(xml(child_elt) for child_elt in self.__content.getchildren())
def __iter__(self):
return self.iterelts()
def __len__(self):
return len(self.__content.getchildren())
def __path_from_list(self,tag_list):
return './/' + '//'.join(self.__prefix + tag for tag in tag_list)
def nav(self,*tag_list):
path = self.__path_from_list(tag_list)
return self.find(path)
def navlist(self,*tag_list):
return self.findall(self.__path_from_list(tag_list))
def find(self,path):
elt = self.__content.find(path)
return xml(elt) if elt != None else None
def findall(self,path):
return [xml(elt) for elt in self.__content.findall(path)]
def join(self,iterable):
"""
Usage:
elt.join(iterable)
returns list of elements from iterable separated by elt
Example:
xml('html', xml('body', *xml('br').join(xml('span',text) for text in ['foo','bar','baz'])))
"""
join_list = []
for elt in iterable:
assert type(elt) == xml
join_list.append(elt)
join_list.append(self)
if len(join_list) > 0:
join_list.pop()
return join_list
def extend(self,iterable):
for elt in iterable:
assert type(elt) == xml
self.append(elt)
def test1():
class xmldict(dict):
def __xml__(self):
xml_elt = xml('dict')
for key in self:
xml_elt.append(xml('dictent',xml('key',str(key)),
xml('value',str(self[key]))))
return xml_elt
e = xmldict()
e['foo'] = 'bar'
assert repr(xml(e)) == "