{ "info": { "author": "saaj", "author_email": "mail@saaj.me", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries" ], "description": ".. image:: https://badge.fury.io/py/Xmlify.png\r\n :target: https://pypi.python.org/pypi/Xmlify\r\n\r\n======\r\nXmlify\r\n======\r\nXmlify is simple and fast Python built-in type XML serialiser. Its purpose is to convert\r\nnested structures that are composed of types like ``dict``, ``list``, ``tuple``, ``str``, \r\n``int``, etc. It has no dependencies, uses ``xml.etree.cElementTree`` and produces XML \r\nstructure suitable for humans to read.\r\n\r\nUse case\r\n========\r\nI use it for structured logging into MySQL. Later, when I need to investigation an incident,\r\nI can further narrow the result set using `MySQL XML functions \r\n`_. You can\r\nuse it for something else.\r\n\r\nResult markup\r\n=============\r\nBecause the XML tree is constructed only using ``xml.etree.cElementTree`` the output is\r\nalways valid XML. But it is more restrictive to tag names. Output tag names avoid colon \r\n(XML namespaces) and are ASCII-only, even though the specification `permits Unicode \r\ncodepoints `_. It was to simplify things, \r\nas there was no benefit of having Unicode tags, and to maximise XML parser compatibility. \r\n\r\nUnicode tag names are hex-encoded and prefixed with ``x``. XML-incompatible binary values\r\nare hex-encoded in the same way. XML-incompatible ASCII characters in tag names are replaced \r\nwith underscore. If tag name starts with a digit it is prefixed with ``n``. Though, it's easy\r\nto override. The following regular expressions control substitution and tag's first character\r\nmatch. You can also monkeypatch ``xmlify._key`` completely. \r\n\r\n.. sourcecode:: python\r\n\r\n xmlify._notFirstCharRe = re.compile(r'[^a-z_]{1}', re.IGNORECASE)\r\n xmlify._notOtherCharsRe = re.compile(r'[^a-z0-9_\\-\\.]', re.IGNORECASE)\r\n\r\nThe type information isn't preserved intentionally to make the output easier to read to a human.\r\nIf you need to preserve type information or to convert XML to objects two-way, just use stdlib's\r\n``xmlrpclib.dumps``/``xmlrpclib.loads``. \r\n\r\nUsage\r\n=====\r\nThis is the public API:\r\n\r\n.. sourcecode:: python\r\n\r\n def dump(obj, fp, root = 'data', declaration = False): pass\r\n \r\n def dumps(obj, root = 'data', declaration = False): pass\r\n \r\nUse it like:\r\n\r\n.. sourcecode:: python\r\n\r\n import datetime\r\n import xmlify\r\n \r\n d = {\r\n 'python' : {\r\n 2 : {\r\n 2.7 : {\r\n 'version' : (2, 7, 10),\r\n 'date' : datetime.date(2015, 5, 23) \r\n }\r\n },\r\n 3 : {\r\n 3.3 : {\r\n 'version' : (3, 3, 6),\r\n 'date' : datetime.date(2014, 10, 12) \r\n },\r\n 3.4 : {\r\n 'version' : (3, 4, 3),\r\n 'date' : datetime.date(2015, 2, 25) \r\n } \r\n }\r\n }\r\n }\r\n print(xmlify.dumps(d))\r\n\r\nIt prints the following XML (indented separately):\r\n \r\n.. sourcecode:: xml\r\n\r\n \r\n \r\n \r\n \r\n 2015-05-23\r\n \r\n 2\r\n 7\r\n 10\r\n \r\n \r\n \r\n \r\n \r\n 2014-10-12\r\n \r\n 3\r\n 3\r\n 6\r\n \r\n \r\n \r\n 2015-02-25\r\n \r\n 3\r\n 4\r\n 3\r\n \r\n \r\n \r\n \r\n \r\n \r\nSimple?\r\n=======\r\nIt's worth just 14 LLOC of a `recursive function \r\n`_. The rest ~100 LLOC\r\nis supporting code that goes in line with Pareto principle.\r\n\r\nFast?\r\n=====\r\n.. sourcecode:: bash\r\n\r\n $ python -c 'import os; print(len(os.environ))'\r\n 58\r\n $ python2.7 -m timeit 'import os,xmlify; xmlify.dumps(os.environ)'\r\n 1000 loops, best of 3: 987 usec per loop\r\n $ python3.3 -m timeit 'import os,xmlify; xmlify.dumps(os.environ)'\r\n 1000 loops, best of 3: 1.62 msec per loop\r\n $ pypy -m timeit 'import os,xmlify; xmlify.dumps(os.environ)'\r\n 1000 loops, best of 3: 193 usec per loop\r\n \r\nInventing own wheel\r\n===================\r\nNIH was not the case \u2013 even though I already had a working code I would happily have used an\r\nexisting library that fits my needs. At the Cheese Shop there were several groups of libraries \r\nthat do the same or closely related thing:\r\n\r\n* Mappers that need schema up-front\r\n* Libraries that need to build dependencies with OS package dependencies, e.g. lxml\r\n* Marshallers that try to preserve type information, thus making result markup hard to read\r\n* Libraries that build XML tree manually with strings and thus with potential escaping issues\r\n* Just broken\r\n\r\nI the end I just decided to package the code I had.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://bitbucket.org/saaj/xmlify", "keywords": "python xml", "license": "LGPL-2.1+", "maintainer": "", "maintainer_email": "", "name": "Xmlify", "package_url": "https://pypi.org/project/Xmlify/", "platform": "Any", "project_url": "https://pypi.org/project/Xmlify/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://bitbucket.org/saaj/xmlify" }, "release_url": "https://pypi.org/project/Xmlify/0.1.1/", "requires_dist": null, "requires_python": null, "summary": "Simple and fast Python built-in type XML serialiser", "version": "0.1.1" }, "last_serial": 2380698, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "b9dca511da3c2fb1aabd44bfcc660d6d", "sha256": "07cec4669193924e679c46a68b8bb25c2878e28837f101e2384820a90523c914" }, "downloads": -1, "filename": "Xmlify-0.1.0.tar.gz", "has_sig": false, "md5_digest": "b9dca511da3c2fb1aabd44bfcc660d6d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5888, "upload_time": "2015-06-02T19:31:21", "url": "https://files.pythonhosted.org/packages/26/68/8c4aef8aa9da2e13fa9e215e8826d4f15ffb5b718fd1925e1c22a3d280d0/Xmlify-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "18d08194e0cf97a3fdaff9ea88f6899a", "sha256": "1a34e3fb2cb91f35036ff474c81f01d1fff4fcf271815b60f51b42839efc12dc" }, "downloads": -1, "filename": "Xmlify-0.1.1.tar.gz", "has_sig": false, "md5_digest": "18d08194e0cf97a3fdaff9ea88f6899a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5941, "upload_time": "2015-06-09T18:54:36", "url": "https://files.pythonhosted.org/packages/d6/8a/d5b77b9d8d7c2acc539e608c37cb84b0c057f4ec088d66d682467150ddaf/Xmlify-0.1.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "18d08194e0cf97a3fdaff9ea88f6899a", "sha256": "1a34e3fb2cb91f35036ff474c81f01d1fff4fcf271815b60f51b42839efc12dc" }, "downloads": -1, "filename": "Xmlify-0.1.1.tar.gz", "has_sig": false, "md5_digest": "18d08194e0cf97a3fdaff9ea88f6899a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5941, "upload_time": "2015-06-09T18:54:36", "url": "https://files.pythonhosted.org/packages/d6/8a/d5b77b9d8d7c2acc539e608c37cb84b0c057f4ec088d66d682467150ddaf/Xmlify-0.1.1.tar.gz" } ] }