adding xmlbuilder
authorTony Mack <tmack@cs.princeton.edu>
Tue, 16 Feb 2010 17:38:40 +0000 (17:38 +0000)
committerTony Mack <tmack@cs.princeton.edu>
Tue, 16 Feb 2010 17:38:40 +0000 (17:38 +0000)
13 files changed:
xmlbuilder-0.9/LICENSE [new file with mode: 0644]
xmlbuilder-0.9/MANIFEST.in [new file with mode: 0644]
xmlbuilder-0.9/PKG-INFO [new file with mode: 0644]
xmlbuilder-0.9/README.txt [new file with mode: 0644]
xmlbuilder-0.9/setup.cfg [new file with mode: 0644]
xmlbuilder-0.9/setup.py [new file with mode: 0644]
xmlbuilder-0.9/xmlbuilder.egg-info/PKG-INFO [new file with mode: 0644]
xmlbuilder-0.9/xmlbuilder.egg-info/SOURCES.txt [new file with mode: 0644]
xmlbuilder-0.9/xmlbuilder.egg-info/dependency_links.txt [new file with mode: 0644]
xmlbuilder-0.9/xmlbuilder.egg-info/top_level.txt [new file with mode: 0644]
xmlbuilder-0.9/xmlbuilder/__init__.py [new file with mode: 0644]
xmlbuilder-0.9/xmlbuilder/docs/long_descr.rst [new file with mode: 0644]
xmlbuilder-0.9/xmlbuilder/tests/__init__.py [new file with mode: 0644]

diff --git a/xmlbuilder-0.9/LICENSE b/xmlbuilder-0.9/LICENSE
new file mode 100644 (file)
index 0000000..0d0f57c
--- /dev/null
@@ -0,0 +1,21 @@
+The MIT License\r
+\r
+Copyright (c) 2008 Konstantin Danilov aka koder\r
+\r
+Permission is hereby granted, free of charge, to any person obtaining a copy\r
+of this software and associated documentation files (the "Software"), to deal\r
+in the Software without restriction, including without limitation the rights\r
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
+copies of the Software, and to permit persons to whom the Software is\r
+furnished to do so, subject to the following conditions:\r
+\r
+The above copyright notice and this permission notice shall be included in\r
+all copies or substantial portions of the Software.\r
+\r
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
+THE SOFTWARE.\r
diff --git a/xmlbuilder-0.9/MANIFEST.in b/xmlbuilder-0.9/MANIFEST.in
new file mode 100644 (file)
index 0000000..207725e
--- /dev/null
@@ -0,0 +1,2 @@
+include xmlbuild/docs *.rst\r
+include . LICENSE
\ No newline at end of file
diff --git a/xmlbuilder-0.9/PKG-INFO b/xmlbuilder-0.9/PKG-INFO
new file mode 100644 (file)
index 0000000..d931c15
--- /dev/null
@@ -0,0 +1,80 @@
+Metadata-Version: 1.0\r
+Name: xmlbuilder\r
+Version: 0.9\r
+Summary: Pythonic way to create xml files\r
+Home-page: http://pypi.python.org/pypi/xmlbuilder\r
+Author: koder\r
+Author-email: koder_dot_mail@gmail_dot_com\r
+License: MIT\r
+Download-URL: http://pypi.python.org/pypi/xmlbuilder\r
+Description: Example of usage:\r
+        -----------------\r
+        \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 &lt;&lt; ('node',{'val':i}) for i in range(10)]\r
+        \r
+        print str(x)\r
+        \r
+        will print\r
+        \r
+        &lt;root a="1"&gt;\r
+        &lt;data&gt;\r
+        &lt;node val="0" /&gt;\r
+        &lt;node val="1" /&gt;\r
+        &lt;node val="2" /&gt;\r
+        &lt;node val="3" /&gt;\r
+        &lt;node val="4" /&gt;\r
+        &lt;node val="5" /&gt;\r
+        &lt;node val="6" /&gt;\r
+        &lt;node val="7" /&gt;\r
+        &lt;node val="8" /&gt;\r
+        &lt;node val="9" /&gt;\r
+        &lt;/data&gt;\r
+        &lt;/root&gt;\r
+        \r
+        Mercurial repo:http://hg.assembla.com/MyPackages/\r
+        \r
+        Documentations\r
+        --------------\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 `&lt;&lt;` operator for simple cases -\r
+        text and tag without childs.\r
+        \r
+        First we need to create xmlbuilder\r
+        \r
+        from xmlbuilder import XMLBuilder\r
+        # params - encoding = 'utf8',\r
+        # builder = None, - ElementTree.TreeBuilder\r
+        # tab_level = None, - current tab l;evel - for formatted output only\r
+        # format = False, - create formatted output\r
+        # tab_step = " " * 4 - indentation step\r
+        xml = XMLBuilder()\r
+        \r
+        \r
+        Use `with` statement to make document structure\r
+        #create and open tag 'root_tag' with text 'text' and attributes\r
+        with xml.root_tag(text,attr1=val1,attr2=val2):\r
+        #create and open tag 'sub_tag'\r
+        with xml.sub_tag(text,attr3=val3):\r
+        #create tag which are not valid python identificator\r
+        with xml('one-more-sub-tag',attr7=val37):\r
+        xml &lt;&lt; "Some textual data"\r
+        #here tag 'one-more-sub-tag' are closed\r
+        #Tags without children can be created using `&lt;&lt;` operator\r
+        for val in range(15):\r
+        xml &lt;&lt; ('message',"python rocks!"[:i])\r
+        #create 15 child tag like &lt;message&gt; python r&lt;/message&gt;\r
+        #all tags closed\r
+        node = ~x # get etree.ElementTree object\r
+        xml_data = str(x)\r
+        unicode_xml_data = unicode(x)\r
+        \r
+Keywords: xml\r
+Platform: UNKNOWN\r
diff --git a/xmlbuilder-0.9/README.txt b/xmlbuilder-0.9/README.txt
new file mode 100644 (file)
index 0000000..7a7131f
--- /dev/null
@@ -0,0 +1 @@
+Pythonic way to build xml files
\ No newline at end of file
diff --git a/xmlbuilder-0.9/setup.cfg b/xmlbuilder-0.9/setup.cfg
new file mode 100644 (file)
index 0000000..b14b0bc
--- /dev/null
@@ -0,0 +1,5 @@
+[egg_info]\r
+tag_build = \r
+tag_date = 0\r
+tag_svn_revision = 0\r
+\r
diff --git a/xmlbuilder-0.9/setup.py b/xmlbuilder-0.9/setup.py
new file mode 100644 (file)
index 0000000..931cb31
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python\r
+#-------------------------------------------------------------------------------\r
+import os\r
+import sys\r
+import glob\r
+import os.path\r
+from setuptools import setup\r
+#from distutils.core import setup\r
+#-------------------------------------------------------------------------------\r
+if 'upload' in sys.argv:\r
+    # for .pypirc file\r
+    try:\r
+        os.environ['HOME']\r
+    except KeyError:\r
+        os.environ['HOME'] = '..\\'\r
+#-------------------------------------------------------------------------------\r
+fpath = lambda x : os.path.join(*x.split('/'))\r
+#-------------------------------------------------------------------------------\r
+PYPI_URL = 'http://pypi.python.org/pypi/xmlbuilder'\r
+ld = open(fpath('xmlbuilder/docs/long_descr.rst')).read()\r
+ld = ld.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;')\r
+setup(\r
+    name = "xmlbuilder",\r
+    fullname = "xmlbuilder",\r
+    version = "0.9",\r
+    packages = ["xmlbuilder"],\r
+    package_dir = {'xmlbuilder':'xmlbuilder'},\r
+    author = "koder",\r
+    author_email = "koder_dot_mail@gmail_dot_com",\r
+    maintainer = 'koder',\r
+    maintainer_email = "koder_dot_mail@gmail_dot_com",\r
+    description = "Pythonic way to create xml files",\r
+    license = "MIT",\r
+    keywords = "xml",\r
+    test_suite = "xml_buider.tests",\r
+    url = PYPI_URL,\r
+    download_url = PYPI_URL,\r
+    long_description = ld,\r
+    #include_package_data = True,\r
+    #package_data = {'xmlbuilder':["docs/*.rst"]},\r
+    #data_files = [('', ['xmlbuilder/docs/long_descr.rst'])]\r
+)\r
+#-------------------------------------------------------------------------------\r
diff --git a/xmlbuilder-0.9/xmlbuilder.egg-info/PKG-INFO b/xmlbuilder-0.9/xmlbuilder.egg-info/PKG-INFO
new file mode 100644 (file)
index 0000000..d931c15
--- /dev/null
@@ -0,0 +1,80 @@
+Metadata-Version: 1.0\r
+Name: xmlbuilder\r
+Version: 0.9\r
+Summary: Pythonic way to create xml files\r
+Home-page: http://pypi.python.org/pypi/xmlbuilder\r
+Author: koder\r
+Author-email: koder_dot_mail@gmail_dot_com\r
+License: MIT\r
+Download-URL: http://pypi.python.org/pypi/xmlbuilder\r
+Description: Example of usage:\r
+        -----------------\r
+        \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 &lt;&lt; ('node',{'val':i}) for i in range(10)]\r
+        \r
+        print str(x)\r
+        \r
+        will print\r
+        \r
+        &lt;root a="1"&gt;\r
+        &lt;data&gt;\r
+        &lt;node val="0" /&gt;\r
+        &lt;node val="1" /&gt;\r
+        &lt;node val="2" /&gt;\r
+        &lt;node val="3" /&gt;\r
+        &lt;node val="4" /&gt;\r
+        &lt;node val="5" /&gt;\r
+        &lt;node val="6" /&gt;\r
+        &lt;node val="7" /&gt;\r
+        &lt;node val="8" /&gt;\r
+        &lt;node val="9" /&gt;\r
+        &lt;/data&gt;\r
+        &lt;/root&gt;\r
+        \r
+        Mercurial repo:http://hg.assembla.com/MyPackages/\r
+        \r
+        Documentations\r
+        --------------\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 `&lt;&lt;` operator for simple cases -\r
+        text and tag without childs.\r
+        \r
+        First we need to create xmlbuilder\r
+        \r
+        from xmlbuilder import XMLBuilder\r
+        # params - encoding = 'utf8',\r
+        # builder = None, - ElementTree.TreeBuilder\r
+        # tab_level = None, - current tab l;evel - for formatted output only\r
+        # format = False, - create formatted output\r
+        # tab_step = " " * 4 - indentation step\r
+        xml = XMLBuilder()\r
+        \r
+        \r
+        Use `with` statement to make document structure\r
+        #create and open tag 'root_tag' with text 'text' and attributes\r
+        with xml.root_tag(text,attr1=val1,attr2=val2):\r
+        #create and open tag 'sub_tag'\r
+        with xml.sub_tag(text,attr3=val3):\r
+        #create tag which are not valid python identificator\r
+        with xml('one-more-sub-tag',attr7=val37):\r
+        xml &lt;&lt; "Some textual data"\r
+        #here tag 'one-more-sub-tag' are closed\r
+        #Tags without children can be created using `&lt;&lt;` operator\r
+        for val in range(15):\r
+        xml &lt;&lt; ('message',"python rocks!"[:i])\r
+        #create 15 child tag like &lt;message&gt; python r&lt;/message&gt;\r
+        #all tags closed\r
+        node = ~x # get etree.ElementTree object\r
+        xml_data = str(x)\r
+        unicode_xml_data = unicode(x)\r
+        \r
+Keywords: xml\r
+Platform: UNKNOWN\r
diff --git a/xmlbuilder-0.9/xmlbuilder.egg-info/SOURCES.txt b/xmlbuilder-0.9/xmlbuilder.egg-info/SOURCES.txt
new file mode 100644 (file)
index 0000000..57272a8
--- /dev/null
@@ -0,0 +1,11 @@
+LICENSE
+MANIFEST.in
+README.txt
+setup.py
+xmlbuilder/__init__.py
+xmlbuilder.egg-info/PKG-INFO
+xmlbuilder.egg-info/SOURCES.txt
+xmlbuilder.egg-info/dependency_links.txt
+xmlbuilder.egg-info/top_level.txt
+xmlbuilder/docs/long_descr.rst
+xmlbuilder/tests/__init__.py
\ No newline at end of file
diff --git a/xmlbuilder-0.9/xmlbuilder.egg-info/dependency_links.txt b/xmlbuilder-0.9/xmlbuilder.egg-info/dependency_links.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/xmlbuilder-0.9/xmlbuilder.egg-info/top_level.txt b/xmlbuilder-0.9/xmlbuilder.egg-info/top_level.txt
new file mode 100644 (file)
index 0000000..9f1d486
--- /dev/null
@@ -0,0 +1 @@
+xmlbuilder
diff --git a/xmlbuilder-0.9/xmlbuilder/__init__.py b/xmlbuilder-0.9/xmlbuilder/__init__.py
new file mode 100644 (file)
index 0000000..1be17b0
--- /dev/null
@@ -0,0 +1,153 @@
+#!/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
diff --git a/xmlbuilder-0.9/xmlbuilder/docs/long_descr.rst b/xmlbuilder-0.9/xmlbuilder/docs/long_descr.rst
new file mode 100644 (file)
index 0000000..4e82bc8
--- /dev/null
@@ -0,0 +1,68 @@
+Example of usage:\r
+-----------------\r
+\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
+print str(x)\r
+\r
+will print\r
+\r
+<root a="1">\r
+    <data>\r
+        <node val="0" />\r
+        <node val="1" />\r
+        <node val="2" />\r
+        <node val="3" />\r
+        <node val="4" />\r
+        <node val="5" />\r
+        <node val="6" />\r
+        <node val="7" />\r
+        <node val="8" />\r
+        <node val="9" />\r
+    </data>\r
+</root>\r
+\r
+Mercurial repo:http://hg.assembla.com/MyPackages/\r
+\r
+Documentations\r
+--------------\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
+First we need to create xmlbuilder\r
+\r
+    from xmlbuilder import XMLBuilder\r
+    # params - encoding = 'utf8',\r
+    # builder = None, - ElementTree.TreeBuilder \r
+    # tab_level = None, - current tab l;evel - for formatted output only\r
+    # format = False, - create formatted output\r
+    # tab_step = " " * 4 - indentation step\r
+    xml = XMLBuilder()\r
+\r
+\r
+Use `with` statement to make document structure\r
+    #create and open tag 'root_tag' with text 'text' and attributes\r
+    with xml.root_tag(text,attr1=val1,attr2=val2):\r
+        #create and open tag 'sub_tag'\r
+        with xml.sub_tag(text,attr3=val3):\r
+            #create tag which are not valid python identificator\r
+            with xml('one-more-sub-tag',attr7=val37):\r
+                xml << "Some textual data"\r
+            #here tag 'one-more-sub-tag' are closed\r
+                       #Tags without children can be created using `<<` operator\r
+            for val in range(15):\r
+                xml << ('message',"python rocks!"[:i])\r
+            #create 15 child tag like <message> python r</message>\r
+    #all tags closed\r
+    node = ~x # get etree.ElementTree object\r
+    xml_data = str(x)\r
+    unicode_xml_data = unicode(x)\r
diff --git a/xmlbuilder-0.9/xmlbuilder/tests/__init__.py b/xmlbuilder-0.9/xmlbuilder/tests/__init__.py
new file mode 100644 (file)
index 0000000..67eaa67
--- /dev/null
@@ -0,0 +1,99 @@
+#!/usr/bin/env python\r
+from __future__ import with_statement\r
+#-------------------------------------------------------------------------------\r
+import unittest\r
+from xml.etree.ElementTree import fromstring\r
+#-------------------------------------------------------------------------------\r
+from xmlbuilder import XMLBuilder\r
+#-------------------------------------------------------------------------------\r
+def xmlStructureEqual(xml1,xml2):\r
+    tree1 = fromstring(xml1)\r
+    tree2 = fromstring(xml2)\r
+    return _xmlStructureEqual(tree1,tree2)\r
+#-------------------------------------------------------------------------------\r
+def _xmlStructureEqual(tree1,tree2):\r
+    if tree1.tag != tree2.tag:\r
+        return False\r
+    attr1 = list(tree1.attrib.items())\r
+    attr1.sort()\r
+    attr2 = list(tree2.attrib.items())\r
+    attr2.sort()\r
+    if attr1 != attr2:\r
+        return False\r
+    return tree1.getchildren() == tree2.getchildren()\r
+#-------------------------------------------------------------------------------\r
+result1 = \\r
+"""\r
+<root>\r
+    <array />\r
+    <array len="10">\r
+        <el val="0" />\r
+        <el val="1">xyz</el>\r
+        <el val="2">abc</el>\r
+        <el val="3" />\r
+        <el val="4" />\r
+        <el val="5" />\r
+        <sup-el val="23">test  </sup-el>\r
+    </array>\r
+</root>\r
+""".strip()\r
+#-------------------------------------------------------------------------------\r
+class TestXMLBuilder(unittest.TestCase):\r
+    def testShift(self):\r
+        xml = (XMLBuilder() << ('root',))\r
+        self.assertEqual(str(xml),"<root />")\r
+        \r
+        xml = XMLBuilder()\r
+        xml << ('root',"some text")\r
+        self.assertEqual(str(xml),"<root>some text</root>")\r
+        \r
+        xml = XMLBuilder()\r
+        xml << ('root',{'x':1,'y':'2'})\r
+        self.assert_(xmlStructureEqual(str(xml),"<root x='1' y='2'>some text</root>"))\r
+        \r
+        xml = XMLBuilder()\r
+        xml << ('root',{'x':1,'y':'2'})\r
+        self.assert_(xmlStructureEqual(str(xml),"<root x='1' y='2'></root>"))\r
+\r
+        xml = XMLBuilder()\r
+        xml << ('root',{'x':1,'y':'2'})\r
+        self.assert_(not xmlStructureEqual(str(xml),"<root x='2' y='2'></root>"))\r
+\r
+        \r
+        xml = XMLBuilder()\r
+        xml << ('root',"gonduras.ua",{'x':1,'y':'2'})\r
+        self.assert_(xmlStructureEqual(str(xml),"<root x='1' y='2'>gonduras.ua</root>"))\r
+        \r
+        xml = XMLBuilder()\r
+        xml << ('root',"gonduras.ua",{'x':1,'y':'2'})\r
+        self.assert_(xmlStructureEqual(str(xml),"<root x='1' y='2'>gonduras.com</root>"))\r
+    #---------------------------------------------------------------------------\r
+    def testWith(self):\r
+        xml = XMLBuilder()\r
+        with xml.root(lenght = 12):\r
+            pass\r
+        self.assertEqual(str(xml),'<root lenght="12" />')\r
+        \r
+        xml = XMLBuilder()\r
+        with xml.root():\r
+            xml << "text1" << "text2" << ('some_node',)\r
+        self.assertEqual(str(xml),"<root>text1text2<some_node /></root>")\r
+    #---------------------------------------------------------------------------\r
+    def testFormat(self):\r
+        x = XMLBuilder('utf-8',format = True)\r
+        with x.root():\r
+            x << ('array',)\r
+            with x.array(len = 10):\r
+                with x.el(val = 0):\r
+                    pass\r
+                with x.el('xyz',val = 1):\r
+                    pass\r
+                x << ("el","abc",{'val':2}) << ('el',dict(val=3))\r
+                x << ('el',dict(val=4)) << ('el',dict(val='5'))\r
+                with x('sup-el',val = 23):\r
+                    x << "test  "\r
+        self.assertEqual(str(x),result1)\r
+#-------------------------------------------------------------------------------\r
+if __name__ == '__main__':\r
+    unittest.main()\r
+#-------------------------------------------------------------------------------\r