2 #-------------------------------------------------------------------------------
3 from __future__ import with_statement
4 #-------------------------------------------------------------------------------
5 from xml.etree.ElementTree import TreeBuilder,tostring
6 #-------------------------------------------------------------------------------
7 __all__ = ["XMLBuilder"]
9 XMLBuilder is simple library build on top of ElementTree.TreeBuilder to
10 simplify xml files creation as much as possible. Althow it can produce
11 structured result with identated child tags. `XMLBuilder` use python `with`
12 statement to define xml tag levels and `<<` operator for simple cases -
13 text and tag without childs.
15 from __future__ import with_statement
16 from xmlbuilder import XMLBuilder
17 x = XMLBuilder(format=True)
20 [x << ('node',{'val':i}) for i in range(10)]
25 #-------------------------------------------------------------------------------
26 class _XMLNode(object):
27 """Class for internal usage"""
28 def __init__(self,parent,name,builder):
29 self.builder = builder
35 def __call__(self,*dt,**mp):
38 self.builder.data(text)
40 self.text.append(text)
42 raise ValueError("Can't add attributes to already opened element")
43 smp = dict((k,str(v)) for k,v in mp.items())
44 self.attrs.update(smp)
48 self.builder.start(self.name,self.attrs)
49 self.builder.data("".join(self.text))
52 def __exit__(self,x,y,z):
54 self.builder.end(self.name)
56 #-------------------------------------------------------------------------------
57 class XMLBuilder(object):
58 """XmlBuilder(encoding = 'utf-8', # result xml file encoding
59 builder = None, #etree.TreeBuilder or compatible class
60 tab_level = None, #current tabulation level - string
61 format = False, # make formatted output
62 tab_step = " " * 4) # tabulation step
63 use str(builder) or unicode(builder) to get xml text or
64 ~builder to obtaine etree.ElementTree
66 def __init__(self,encoding = 'utf-8',
71 self.__builder = builder or TreeBuilder()
72 self.__encoding = encoding
76 if tab_level is not None:
78 raise ValueError("format is False, but tab_level not None")
79 self.__tab_level = tab_level # current format level
80 self.__tab_step = tab_step # format step
81 self.__has_sub_tag = False # True, if current tag had childrens
83 # called from _XMLNode when tag opened
84 def __iadd__(self,val):
85 self.__has_sub_tag = False
86 if self.__tab_level is not None:
87 self.__builder.data("\n" + self.__tab_level)
88 self.__tab_level += self.__tab_step
90 # called from XMLNode when tag closed
91 def __isub__(self,val):
92 if self.__tab_level is not None:
93 self.__tab_level = self.__tab_level[:-len(self.__tab_step)]
94 if self.__has_sub_tag:
95 self.__builder.data("\n" + self.__tab_level)
96 self.__has_sub_tag = True
98 def __getattr__(self,name):
99 return _XMLNode(self,name,self.__builder)
100 def __call__(self,name,*dt,**mp):
101 x = _XMLNode(self,name,self.__builder)
104 #create new tag or add text
105 #possible shift values
107 #tuple(string1,string2,dict) - new tag with name string1,attrs = dict,and text string2
108 #dict and string2 are optional
109 def __lshift__(self,val):
110 if isinstance(val,basestring):
111 self.__builder.data(val)
113 self.__has_sub_tag = True
114 assert hasattr(val,'__len__'),\
115 'Shifted value should be tuple or list like object not %r' % val
116 assert hasattr(val,'__getitem__'),\
117 'Shifted value should be tuple or list like object not %r' % val
126 if isinstance(val[1],basestring):
132 if self.__tab_level is not None:
133 self.__builder.data("\n" + self.__tab_level)
134 self.__builder.start(name,
135 dict((k,str(v)) for k,v in attrs.items()))
137 self.__builder.data(text)
138 self.__builder.end(name)
139 return self # to allow xml << some1 << some2 << some3
141 def __invert__(self):
142 if self.__node is not None:
144 self.__node = self.__builder.close()
147 """return generated xml"""
148 return tostring(~self,self.__encoding)
149 def __unicode__(self):
150 """return generated xml"""
151 res = tostring(~self,self.__encoding)
152 return res.decode(self.__encoding)
153 #-------------------------------------------------------------------------------