summaryrefslogtreecommitdiffstats
path: root/Lib/xml/etree/ElementTree.py
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2019-08-23 14:44:25 (GMT)
committerGitHub <noreply@github.com>2019-08-23 14:44:25 (GMT)
commitb5d3ceea48c181b3e2c6c67424317afed606bd39 (patch)
tree6ee510b9c8db32251e3aed8a16b186ac08c3f04f /Lib/xml/etree/ElementTree.py
parent81446fd0d4fa60042ac2752350f31004324510f9 (diff)
downloadcpython-b5d3ceea48c181b3e2c6c67424317afed606bd39.zip
cpython-b5d3ceea48c181b3e2c6c67424317afed606bd39.tar.gz
cpython-b5d3ceea48c181b3e2c6c67424317afed606bd39.tar.bz2
bpo-14465: Add an indent() function to xml.etree.ElementTree to pretty-print XML trees (GH-15200)
Diffstat (limited to 'Lib/xml/etree/ElementTree.py')
-rw-r--r--Lib/xml/etree/ElementTree.py53
1 files changed, 52 insertions, 1 deletions
diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py
index 645e999..431ecd0 100644
--- a/Lib/xml/etree/ElementTree.py
+++ b/Lib/xml/etree/ElementTree.py
@@ -76,7 +76,7 @@ __all__ = [
"dump",
"Element", "ElementTree",
"fromstring", "fromstringlist",
- "iselement", "iterparse",
+ "indent", "iselement", "iterparse",
"parse", "ParseError",
"PI", "ProcessingInstruction",
"QName",
@@ -1185,6 +1185,57 @@ def dump(elem):
if not tail or tail[-1] != "\n":
sys.stdout.write("\n")
+
+def indent(tree, space=" ", level=0):
+ """Indent an XML document by inserting newlines and indentation space
+ after elements.
+
+ *tree* is the ElementTree or Element to modify. The (root) element
+ itself will not be changed, but the tail text of all elements in its
+ subtree will be adapted.
+
+ *space* is the whitespace to insert for each indentation level, two
+ space characters by default.
+
+ *level* is the initial indentation level. Setting this to a higher
+ value than 0 can be used for indenting subtrees that are more deeply
+ nested inside of a document.
+ """
+ if isinstance(tree, ElementTree):
+ tree = tree.getroot()
+ if level < 0:
+ raise ValueError(f"Initial indentation level must be >= 0, got {level}")
+ if not len(tree):
+ return
+
+ # Reduce the memory consumption by reusing indentation strings.
+ indentations = ["\n" + level * space]
+
+ def _indent_children(elem, level):
+ # Start a new indentation level for the first child.
+ child_level = level + 1
+ try:
+ child_indentation = indentations[child_level]
+ except IndexError:
+ child_indentation = indentations[level] + space
+ indentations.append(child_indentation)
+
+ if not elem.text or not elem.text.strip():
+ elem.text = child_indentation
+
+ for child in elem:
+ if len(child):
+ _indent_children(child, child_level)
+ if not child.tail or not child.tail.strip():
+ child.tail = child_indentation
+
+ # Dedent after the last child by overwriting the previous indentation.
+ if not child.tail.strip():
+ child.tail = indentations[level]
+
+ _indent_children(tree, 0)
+
+
# --------------------------------------------------------------------
# parsing