-#!/usr/bin/env python\r
-#-------------------------------------------------------------------------------\r
-from __future__ import with_statement\r
-#-------------------------------------------------------------------------------\r
-from xml.etree.ElementTree import TreeBuilder,tostring\r
-#-------------------------------------------------------------------------------\r
-__all__ = ["XMLBuilder"]\r
-__doc__ = """\r
-XMLBuilder is simple library build on top of ElementTree.TreeBuilder to\r
-simplify xml files creation as much as possible. Althow it can produce\r
-structured result with identated child tags. `XMLBuilder` use python `with`\r
-statement to define xml tag levels and `<<` operator for simple cases -\r
-text and tag without childs.\r
-\r
-from __future__ import with_statement\r
-from xmlbuilder import XMLBuilder\r
-x = XMLBuilder(format=True)\r
-with x.root(a = 1):\r
- with x.data:\r
- [x << ('node',{'val':i}) for i in range(10)]\r
-\r
-etree_node = ~x\r
-print str(x)\r
-"""\r
-#-------------------------------------------------------------------------------\r
-class _XMLNode(object):\r
- """Class for internal usage"""\r
- def __init__(self,parent,name,builder):\r
- self.builder = builder\r
- self.name = name\r
- self.text = []\r
- self.attrs = {}\r
- self.entered = False\r
- self.parent = parent\r
- def __call__(self,*dt,**mp):\r
- text = "".join(dt)\r
- if self.entered:\r
- self.builder.data(text)\r
- else:\r
- self.text.append(text)\r
- if self.entered:\r
- raise ValueError("Can't add attributes to already opened element")\r
- smp = dict((k,str(v)) for k,v in mp.items())\r
- self.attrs.update(smp)\r
- return self\r
- def __enter__(self):\r
- self.parent += 1\r
- self.builder.start(self.name,self.attrs)\r
- self.builder.data("".join(self.text))\r
- self.entered = True\r
- return self\r
- def __exit__(self,x,y,z):\r
- self.parent -= 1\r
- self.builder.end(self.name)\r
- return False\r
-#-------------------------------------------------------------------------------\r
-class XMLBuilder(object):\r
- """XmlBuilder(encoding = 'utf-8', # result xml file encoding\r
- builder = None, #etree.TreeBuilder or compatible class\r
- tab_level = None, #current tabulation level - string\r
- format = False, # make formatted output\r
- tab_step = " " * 4) # tabulation step\r
- use str(builder) or unicode(builder) to get xml text or\r
- ~builder to obtaine etree.ElementTree\r
- """\r
- def __init__(self,encoding = 'utf-8',\r
- builder = None,\r
- tab_level = None,\r
- format = False,\r
- tab_step = " " * 4):\r
- self.__builder = builder or TreeBuilder()\r
- self.__encoding = encoding \r
- if format :\r
- if tab_level is None:\r
- tab_level = ""\r
- if tab_level is not None:\r
- if not format:\r
- raise ValueError("format is False, but tab_level not None")\r
- self.__tab_level = tab_level # current format level\r
- self.__tab_step = tab_step # format step\r
- self.__has_sub_tag = False # True, if current tag had childrens\r
- self.__node = None\r
- # called from _XMLNode when tag opened\r
- def __iadd__(self,val):\r
- self.__has_sub_tag = False\r
- if self.__tab_level is not None:\r
- self.__builder.data("\n" + self.__tab_level)\r
- self.__tab_level += self.__tab_step\r
- return self\r
- # called from XMLNode when tag closed\r
- def __isub__(self,val):\r
- if self.__tab_level is not None:\r
- self.__tab_level = self.__tab_level[:-len(self.__tab_step)]\r
- if self.__has_sub_tag:\r
- self.__builder.data("\n" + self.__tab_level)\r
- self.__has_sub_tag = True\r
- return self\r
- def __getattr__(self,name):\r
- return _XMLNode(self,name,self.__builder)\r
- def __call__(self,name,*dt,**mp):\r
- x = _XMLNode(self,name,self.__builder)\r
- x(*dt,**mp)\r
- return x\r
- #create new tag or add text\r
- #possible shift values\r
- #string - text\r
- #tuple(string1,string2,dict) - new tag with name string1,attrs = dict,and text string2\r
- #dict and string2 are optional\r
- def __lshift__(self,val):\r
- if isinstance(val,basestring):\r
- self.__builder.data(val)\r
- else:\r
- self.__has_sub_tag = True\r
- assert hasattr(val,'__len__'),\\r
- 'Shifted value should be tuple or list like object not %r' % val\r
- assert hasattr(val,'__getitem__'),\\r
- 'Shifted value should be tuple or list like object not %r' % val\r
- name = val[0]\r
- if len(val) == 3:\r
- text = val[1]\r
- attrs = val[2]\r
- elif len(val) == 1:\r
- text = ""\r
- attrs = {}\r
- elif len(val) == 2:\r
- if isinstance(val[1],basestring):\r
- text = val[1]\r
- attrs = {}\r
- else:\r
- text = ""\r
- attrs = val[1]\r
- if self.__tab_level is not None:\r
- self.__builder.data("\n" + self.__tab_level)\r
- self.__builder.start(name,\r
- dict((k,str(v)) for k,v in attrs.items()))\r
- if text:\r
- self.__builder.data(text)\r
- self.__builder.end(name)\r
- return self # to allow xml << some1 << some2 << some3\r
- #close builder\r
- def __invert__(self):\r
- if self.__node is not None:\r
- return self.__node\r
- self.__node = self.__builder.close()\r
- return self.__node\r
- def __str__(self):\r
- """return generated xml"""\r
- return tostring(~self,self.__encoding)\r
- def __unicode__(self):\r
- """return generated xml"""\r
- res = tostring(~self,self.__encoding)\r
- return res.decode(self.__encoding)\r
-#-------------------------------------------------------------------------------\r
+#!/usr/bin/env python
+#-------------------------------------------------------------------------------
+from __future__ import with_statement
+#-------------------------------------------------------------------------------
+from xml.etree.ElementTree import TreeBuilder,tostring
+#-------------------------------------------------------------------------------
+__all__ = ["XMLBuilder"]
+__doc__ = """
+XMLBuilder is simple library build on top of ElementTree.TreeBuilder to
+simplify xml files creation as much as possible. Althow it can produce
+structured result with identated child tags. `XMLBuilder` use python `with`
+statement to define xml tag levels and `<<` operator for simple cases -
+text and tag without childs.
+
+from __future__ import with_statement
+from xmlbuilder import XMLBuilder
+x = XMLBuilder(format=True)
+with x.root(a = 1):
+ with x.data:
+ [x << ('node',{'val':i}) for i in range(10)]
+
+etree_node = ~x
+print str(x)
+"""
+#-------------------------------------------------------------------------------
+class _XMLNode(object):
+ """Class for internal usage"""
+ def __init__(self,parent,name,builder):
+ self.builder = builder
+ self.name = name
+ self.text = []
+ self.attrs = {}
+ self.entered = False
+ self.parent = parent
+ def __call__(self,*dt,**mp):
+ text = "".join(dt)
+ if self.entered:
+ self.builder.data(text)
+ else:
+ self.text.append(text)
+ if self.entered:
+ raise ValueError("Can't add attributes to already opened element")
+ smp = dict((k,str(v)) for k,v in mp.items())
+ self.attrs.update(smp)
+ return self
+ def __enter__(self):
+ self.parent += 1
+ self.builder.start(self.name,self.attrs)
+ self.builder.data("".join(self.text))
+ self.entered = True
+ return self
+ def __exit__(self,x,y,z):
+ self.parent -= 1
+ self.builder.end(self.name)
+ return False
+#-------------------------------------------------------------------------------
+class XMLBuilder(object):
+ """XmlBuilder(encoding = 'utf-8', # result xml file encoding
+ builder = None, #etree.TreeBuilder or compatible class
+ tab_level = None, #current tabulation level - string
+ format = False, # make formatted output
+ tab_step = " " * 4) # tabulation step
+ use str(builder) or unicode(builder) to get xml text or
+ ~builder to obtaine etree.ElementTree
+ """
+ def __init__(self,encoding = 'utf-8',
+ builder = None,
+ tab_level = None,
+ format = False,
+ tab_step = " " * 4):
+ self.__builder = builder or TreeBuilder()
+ self.__encoding = encoding
+ if format :
+ if tab_level is None:
+ tab_level = ""
+ if tab_level is not None:
+ if not format:
+ raise ValueError("format is False, but tab_level not None")
+ self.__tab_level = tab_level # current format level
+ self.__tab_step = tab_step # format step
+ self.__has_sub_tag = False # True, if current tag had childrens
+ self.__node = None
+ # called from _XMLNode when tag opened
+ def __iadd__(self,val):
+ self.__has_sub_tag = False
+ if self.__tab_level is not None:
+ self.__builder.data("\n" + self.__tab_level)
+ self.__tab_level += self.__tab_step
+ return self
+ # called from XMLNode when tag closed
+ def __isub__(self,val):
+ if self.__tab_level is not None:
+ self.__tab_level = self.__tab_level[:-len(self.__tab_step)]
+ if self.__has_sub_tag:
+ self.__builder.data("\n" + self.__tab_level)
+ self.__has_sub_tag = True
+ return self
+ def __getattr__(self,name):
+ return _XMLNode(self,name,self.__builder)
+ def __call__(self,name,*dt,**mp):
+ x = _XMLNode(self,name,self.__builder)
+ x(*dt,**mp)
+ return x
+ #create new tag or add text
+ #possible shift values
+ #string - text
+ #tuple(string1,string2,dict) - new tag with name string1,attrs = dict,and text string2
+ #dict and string2 are optional
+ def __lshift__(self,val):
+ if isinstance(val,basestring):
+ self.__builder.data(val)
+ else:
+ self.__has_sub_tag = True
+ assert hasattr(val,'__len__'),\
+ 'Shifted value should be tuple or list like object not %r' % val
+ assert hasattr(val,'__getitem__'),\
+ 'Shifted value should be tuple or list like object not %r' % val
+ name = val[0]
+ if len(val) == 3:
+ text = val[1]
+ attrs = val[2]
+ elif len(val) == 1:
+ text = ""
+ attrs = {}
+ elif len(val) == 2:
+ if isinstance(val[1],basestring):
+ text = val[1]
+ attrs = {}
+ else:
+ text = ""
+ attrs = val[1]
+ if self.__tab_level is not None:
+ self.__builder.data("\n" + self.__tab_level)
+ self.__builder.start(name,
+ dict((k,str(v)) for k,v in attrs.items()))
+ if text:
+ self.__builder.data(text)
+ self.__builder.end(name)
+ return self # to allow xml << some1 << some2 << some3
+ #close builder
+ def __invert__(self):
+ if self.__node is not None:
+ return self.__node
+ self.__node = self.__builder.close()
+ return self.__node
+ def __str__(self):
+ """return generated xml"""
+ return tostring(~self,self.__encoding)
+ def __unicode__(self):
+ """return generated xml"""
+ res = tostring(~self,self.__encoding)
+ return res.decode(self.__encoding)
+#-------------------------------------------------------------------------------