{
"info": {
"author": "Adrian W\u0142osiak",
"author_email": "adwlosiakh@gmail.com",
"bugtrack_url": null,
"classifiers": [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 3"
],
"description": "**xml_browser.py** - Edit XML documents as a directory structure\n\n.. note:: This is a demo version. I'm publishing it early, so I can get feedback from you. If some people find this utility useful, I'll keep developing (hopefully with some help :)). Otherwise, it will just stay here as a fun idea of mine that I will maybe play around with. As this is a demo version, it lacks quite some features I'm willing to add some day (you can find the list below). Please open an issue if you notice any misconception - I'd like to eliminate them as soon as possible.\n\nxml_browser converts arbitrary XML documents to a directory structure. This enables user to browse and edit XML in a simple and (as the author hopes) intuitive way.\n\nThis utility was written in Python 3, but is intended to be portable. It was just quickly tested under Python 2, so it may be not working in older versions.\n\n.. contents:: Table of contents\n\nWhy?\n====\n\nThe main target is editing XML from within shell scripts. Representing XML as a directory structure makes it easy to do editing with basic shell tools. Also, some advantage of this approach is that operating on a directory structure makes shell code more comprehensive. For example, if script does ``sed`` on ``root,0/some_element,1/0-text`` then you probably suspect what is going on.\n\nxml_browser is easy to get and run in volatile environment. You could just setup virtualenv and install xml_browser with pip, or even just get the script via http. No need to preinstall anything or download precompiled binaries. xml_browser is pure Python utility and has no external dependencies.\n\nHow to use it?\n==============\n\nThe ``makedir``\n---------------\n\nTake following XML as an example::\n\n \n \n This is a xml_browser demo.\n yup\n tail\n \n \n \n\nLet's say above is the content of `example.xml` file. To create a directory structure based on this file, run::\n\n xml_browser.py makedir < example.xml\n\nxml_browser reads data from standard input - that way it is easy to pipe results of a command (e.g. ``curl``) directly, without doing too much of a shell magic, like process substitution.\n\nBy running the command, we'll get following dirtree::\n\n documentRoot,0\n \u251c\u2500\u2500 a,0\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 0-attributes\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 0-text\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 b,0\n \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 0-tail\n \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 0-text\n \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 .tail.ws\n \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 .text.ws\n \u2502\u00a0\u00a0 \u251c\u2500\u2500 .tail.ws\n \u2502\u00a0\u00a0 \u2514\u2500\u2500 .text.ws\n \u251c\u2500\u2500 .text.ws\n \u2514\u2500\u2500 z,1\n \u2514\u2500\u2500 .tail.ws\n\n 3 directories, 10 files\n\nYou can notice directories corresponding with every element from `example.xml` and some files inside them.\nAll directories have suffixes that are appended to element names as an ordering information. This way we know, that ```` element goes before ````. We will discuss ordering in detail later.\n\nWhat about files, why do their names start with ``0-``? The answer is simple - no valid XML tag can start with a number, so it will not clash with any tag name (`text` as a tag name is not that unusual). Tags cannot start with hyphen (``-``) either, but if it was the first character of a filename, then you'd need to use ``--`` in almost every shell command to parse it correctly. Also, ``0-`` is rather easy to type.\n\n`0-attributes` holds information about element attributes in a propfile format, e.g::\n\n a=1\n b= 2\n\nNote that there are no quotes. Leading and trailing whitespaces of a value are taken litteraly (no stripping!). Attribute names can have leading and trailing whitespaces but - in contrary to values - they will be stripped. So, following line of `0-attributes`: ``\" attribute_name = value \"`` will evaluate to ``\"attribute_name\"`` and ``\" value \"`` respectively.\n\n`0-text` contains stripped text of element with a newline appended at the end. `0-tail` is almost the same thing, but a tail is a text that goes right *after* element. It's stripped in the same way.\n\nWhen you edit `0-tail` or `0-text` and assemble directory tree to a XML document you can see that leading and trailing whitespaces are preserved. It is possible thanks to `.text.ws` and `.tail.ws` files. They consist of whitespaces and a ``x`` character somewhere between them. This ``x`` serves as a substitution mark - it will be replaced with stripped text from `0-text`/`0-tail`. Usually we don't need to manipulate whitespaces, so they are kept in hidden files.\n\nObtaining data from directory tree\n..................................\n\nMoving around manually doesn't need explaining, I believe. Let's focus a bit on usage in shell scripts.\n\nFor automated tasks ``find``, ``grep`` and globbing are your friends.\n\nThe simplest case is when you know the structure of your XML::\n\n text_of_b=$(cat documentRoot,0/a,*/b,0/0-text)\n\nThe * is used here just to show, that we can do that this way. Tag names cannot contain commas, so it is used to separate tag name from ordering. Note that * is specified after a comma, so only `a` tag will be matched. if the pattern was ``a*``, then names like ``alaska`` would match as well.\n\nWhat if we want to find every `foo` element in the whole document? Let's try to ``find`` a way::\n\n find root,0 -type d -name \"foo,*\"\n\nWhat if we want to find every `foo` element with a ``bar`` argument having value ``baz``?::\n\n find root,0 -type d -name \"foo,*\" -exec grep -q 'bar=baz' {}/0-attributes -print\n\nLet's expand above case and call a compound command for every match::\n\n find root,0 -type d -name \"foo,*\" -exec grep -q 'bar=baz' {}/0-attributes -print | \\\n while read -r match; do\n cat $match/0-text\n # we could do that in -exec in find or with xargs, but I'm too lazy to come up with a more complex example.\n # that would fit for a loop. But you see, you can run lots of commands here for every hit!\n done\n\nWhat if we want to make above the right way?::\n\n find root,0 -type d -name \"foo,*\" -exec grep -q 'bar=baz' {}/0-attributes -print0 | \\\n while IFS= read -r -d '' match; do\n cat \"$match/0-text\"\n done\n\nWe could do this without ``find`` too, but I consider this less readable - and we need to play around with `IFS`::\n\n IFS=$'\\n'\n for match in $(grep -lR 'bar=baz' root,0/* | grep 'foo,[^/]*/0-attributes'); do\n cat \"$(dirname \"$match\")/0-text\" 2> /dev/null\n done\n\nThese examples are rather lengthy, but not that hard to construct. xml_browser is intended to be used in shell, so using some ``find``, ``grep`` and some loops is not improper.\n\n\nEditing\n-------\n\nEditing data is similar to reading it. You can use ``sed`` or ``awk`` in commands above, so let's focus on xml_browser specific thing - node ordering.\n\nConsider following::\n\n \n \n \n \n \n \n \n Some tail text\n \n\nAs you already know, we'll get following subdirectories inside `reallySimple,0` directory::\n\n a,0 a,1 b,2 a,3 c,4 c,5\n\nEasy. But how to add a node? It's obvious how to append a node at the end (e.g. ``mkdir new,6``, you may want to move `0-tail` to the new last element). But how to insert it between some existing nodes? Time for some theory.\n\nNumbers at the time of assembling directory structure into a XML document are used solely for ordering, so it does not matter if you have, let's say, `a,0`, `a,1`, `over,2` or something like `a,-100`, `a,4.5` and `over,9000` - the result will be exactly the same. You can specify any float.\n\n*But bash sucks at floats!* - you might say. That's true. You can append more commas and numbers to the dirname. So to insert `middle` element between `a,3` and `c,4`, do::\n\n mkdir middle,3,1\n\nYou need to know, that ordering operates on tuples of floats. Tuple for `a,0` is ``(0.0,)``, for `middle,3,1` it's ``(3.0, 1.0)``, so if you create a directory named `foo,3,-3` the tuple will be ``(3.0, -3.0)`` and the element will be placed between `a,3` and `middle,3,1` - that's how tuple ordering work, element by element.\n\nxml_browser's ``makedir`` will always generate subsequent integers starting from 0, so it is possible to access elements easily, as the names are predictable. So if you need to read and manipulate data/nodes, do the reading part first, before you will alter ordering.\n\nThe ``assemble``\n----------------\n\nWhen you're done editting, you can assemble the directory tree to a XML document. Just call::\n\n xml_browser.py assemble documentRoot > result.xml\n\nLike with ``makedir``, result is written on standard output, so you can pipe it to any command or redirect to a file.\n\nPlanned features\n================\n\n- Support for namespaces - ElementTree doesn't handle them correctly.\n- Fancy formatting/generating options\n- Options for creating dirtree - creation mode, handling already existing tree.\n- Waiting for your suggestions!\n\nLicense\n=======\n\nMIT (c) Adrian W\u0142osiak 2016",
"description_content_type": null,
"docs_url": null,
"download_url": "",
"downloads": {
"last_day": -1,
"last_month": -1,
"last_week": -1
},
"home_page": "https://github.com/rasguanabana/xml_browser",
"keywords": "xml editing",
"license": "MIT",
"maintainer": "",
"maintainer_email": "",
"name": "xml-browser",
"package_url": "https://pypi.org/project/xml-browser/",
"platform": "UNKNOWN",
"project_url": "https://pypi.org/project/xml-browser/",
"project_urls": {
"Homepage": "https://github.com/rasguanabana/xml_browser"
},
"release_url": "https://pypi.org/project/xml-browser/0.99.dev2/",
"requires_dist": null,
"requires_python": "",
"summary": "Edit XML documents as a directory structure",
"version": "0.99.dev2"
},
"last_serial": 2434060,
"releases": {
"0.99.dev1": [],
"0.99.dev2": [
{
"comment_text": "",
"digests": {
"md5": "bb43e44777702645750bd2d5702a92ec",
"sha256": "21c572468c89981368abe5bf0b77941e74d09cfd5a31b17df79bfbbb84b76075"
},
"downloads": -1,
"filename": "xml_browser-0.99.dev2-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "bb43e44777702645750bd2d5702a92ec",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": null,
"size": 13474,
"upload_time": "2016-10-31T23:12:26",
"url": "https://files.pythonhosted.org/packages/b3/48/cc582e9763996c43201cafd862abf067ad5bb05439cfb6bc70ddd925115b/xml_browser-0.99.dev2-py2.py3-none-any.whl"
}
]
},
"urls": [
{
"comment_text": "",
"digests": {
"md5": "bb43e44777702645750bd2d5702a92ec",
"sha256": "21c572468c89981368abe5bf0b77941e74d09cfd5a31b17df79bfbbb84b76075"
},
"downloads": -1,
"filename": "xml_browser-0.99.dev2-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "bb43e44777702645750bd2d5702a92ec",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": null,
"size": 13474,
"upload_time": "2016-10-31T23:12:26",
"url": "https://files.pythonhosted.org/packages/b3/48/cc582e9763996c43201cafd862abf067ad5bb05439cfb6bc70ddd925115b/xml_browser-0.99.dev2-py2.py3-none-any.whl"
}
]
}