{"id":6939,"library":"untangle","title":"untangle","description":"untangle is a tiny Python library for parsing XML documents, converting them into easy-to-use Python objects. It simplifies accessing data in XML files using dot notation for elements and dictionary-like access for attributes. The current version is 1.2.1, released in July 2022, and it has an infrequent release cadence.","status":"active","version":"1.2.1","language":"en","source_language":"en","source_url":"https://github.com/stchris/untangle","tags":["xml","parsing","object conversion","lightweight","utility"],"install":[{"cmd":"pip install untangle","lang":"bash","label":"Install with pip"}],"dependencies":[{"reason":"Requires Python 3.7 or newer for version 1.2.1+.","package":"python","optional":false}],"imports":[{"note":"The primary function `parse` is accessed via the top-level `untangle` module.","symbol":"parse","correct":"import untangle\nobj = untangle.parse(...)"}],"quickstart":{"code":"import untangle\n\nxml_data = \"\"\"<?xml version=\"1.0\"?>\n<data>\n    <user id=\"123\" status=\"active\">\n        <name>Alice</name>\n        <email>alice@example.com</email>\n    </user>\n    <user id=\"456\" status=\"inactive\">\n        <name>Bob</name>\n        <email>bob@example.com</email>\n    </user>\n</data>\"\"\"\n\n# Parse the XML string\ndoc = untangle.parse(xml_data)\n\n# Accessing the root element (data)\nprint(f\"Root element tag: {doc.data._tag}\")\n\n# Accessing the first user element and its attributes/cdata\nfirst_user = doc.data.user[0]\nprint(f\"First user ID: {first_user['id']}\")\nprint(f\"First user Status: {first_user['status']}\")\nprint(f\"First user Name: {first_user.name.cdata}\")\nprint(f\"First user Email: {first_user.email.cdata}\")\n\n# Iterating through users\nfor user in doc.data.user:\n    print(f\"User (ID: {user['id']}): {user.name.cdata} <{user.email.cdata}>\")","lang":"python","description":"This quickstart demonstrates how to parse an XML string and access elements, attributes (using dictionary-like syntax), and text content (cdata) using dot notation. Note that sibling elements with the same tag are automatically grouped into a list."},"warnings":[{"fix":"Upgrade to untangle version 1.2.1 or higher. This version includes patches to prevent these SAX vulnerabilities.","message":"Versions 1.2.0 and earlier are vulnerable to XML External Entity (XXE) injection and recursive entity references (Denial of Service). This could allow remote unauthenticated attackers to read local files or cause a DoS condition on the server.","severity":"breaking","affected_versions":"<= 1.2.0"},{"fix":"Ensure your Python environment is 3.7 or newer. If you must use an older Python version (3.4-3.6), you will need to stick to `untangle` versions <= 1.1.1, but be aware of potential security vulnerabilities in those older releases.","message":"Starting with version 1.2.1, `untangle` dropped official support for Python versions 3.4-3.6 and PyPy.","severity":"breaking","affected_versions":"< 1.2.1 (for compatibility with newer Python)"},{"fix":"Be mindful of this transformation when constructing your access paths. Test your expected access patterns carefully to avoid `AttributeError`.","message":"XML element and attribute names containing hyphens (`-`), periods (`.`), or colons (`:`) are automatically converted to underscores (`_`) for attribute-style access in the Python object. For example, an XML tag `<foo-bar/>` will be accessed as `obj.foo_bar`.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always append `.cdata` to the element object when you intend to retrieve its inner text content.","message":"The text content within an XML tag (CDATA) is not accessed directly as the element's value but through a special `.cdata` attribute on the element object (e.g., `element.name.cdata`).","severity":"gotcha","affected_versions":"All versions"},{"fix":"When dealing with elements that might appear multiple times, always be prepared to handle a list (e.g., `for item in parent.item:`). If you expect a single element, direct access (`parent.item`) works, but if the XML structure can vary, consider defensive coding (e.g., checking `isinstance(parent.item, list)` or using `parent.item[0]` if you only want the first).","message":"If an XML document contains multiple sibling elements with the same tag name, `untangle` automatically groups them into a Python list. If there's only one, it's accessed directly as an object.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-15T00:00:00.000Z","next_check":"2026-07-14T00:00:00.000Z","problems":[]}