From 556c97d7ee1fc30fa62d349fbc52b27c085d2529 Mon Sep 17 00:00:00 2001 From: Daniel Mach Date: Mon, 12 Feb 2024 09:06:01 +0100 Subject: [PATCH] Move xml_indent, xml_quote and xml_unquote to osc.util.xml module --- osc/_private/api.py | 42 +++-------------------- osc/core.py | 21 +----------- osc/util/xml.py | 81 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 58 deletions(-) create mode 100644 osc/util/xml.py diff --git a/osc/_private/api.py b/osc/_private/api.py index 71908868bb..09d6e964a1 100644 --- a/osc/_private/api.py +++ b/osc/_private/api.py @@ -7,6 +7,10 @@ import xml.sax.saxutils from xml.etree import ElementTree as ET +from ..util.xml import xml_escape +from ..util.xml import xml_indent +from ..util.xml import xml_unescape + def get(apiurl, path, query=None): """ @@ -205,41 +209,3 @@ def write_xml_node_to_file(node, path, indent=True): if indent: xml_indent(node) ET.ElementTree(node).write(path) - - -def xml_escape(string): - """ - Escape the string so it's safe to use in XML and xpath. - """ - entities = { - "\"": """, - "'": "'", - } - if isinstance(string, bytes): - return xml.sax.saxutils.escape(string.decode("utf-8"), entities=entities).encode("utf-8") - return xml.sax.saxutils.escape(string, entities=entities) - - -def xml_unescape(string): - """ - Decode XML entities in the string. - """ - entities = { - """: "\"", - "'": "'", - } - if isinstance(string, bytes): - return xml.sax.saxutils.unescape(string.decode("utf-8"), entities=entities).encode("utf-8") - return xml.sax.saxutils.unescape(string, entities=entities) - - -def xml_indent(root): - """ - Indent XML so it looks pretty after printing or saving to file. - """ - if hasattr(ET, "indent"): - # ElementTree supports indent() in Python 3.9 and newer - ET.indent(root) - else: - from .. import core as osc_core - osc_core.xmlindent(root) diff --git a/osc/core.py b/osc/core.py index 5194ce0c84..ba3525d5d7 100644 --- a/osc/core.py +++ b/osc/core.py @@ -54,6 +54,7 @@ from .connection import http_request, http_GET, http_POST, http_PUT, http_DELETE from .store import Store from .util.helper import decode_list, decode_it, raw_input, _html_escape +from .util.xml import xml_indent_compat as xmlindent ET_ENCODING = "unicode" @@ -636,26 +637,6 @@ def isexpanded(self): def haserror(self): return self.error is not None -# http://effbot.org/zone/element-lib.htm#prettyprint - - -def xmlindent(elem, level=0): - i = "\n" + level * " " - if isinstance(elem, ET.ElementTree): - elem = elem.getroot() - if len(elem): - if not elem.text or not elem.text.strip(): - elem.text = i + " " - for e in elem: - xmlindent(e, level + 1) - if not e.tail or not e.tail.strip(): - e.tail = i + " " - if not e.tail or not e.tail.strip(): - e.tail = i - else: - if level and (not elem.tail or not elem.tail.strip()): - elem.tail = i - class Project: """ diff --git a/osc/util/xml.py b/osc/util/xml.py new file mode 100644 index 0000000000..166a5c1855 --- /dev/null +++ b/osc/util/xml.py @@ -0,0 +1,81 @@ +""" +Functions that manipulate with XML. +""" + + +import xml.sax.saxutils +from xml.etree import ElementTree as ET + + +def xml_escape(string): + """ + Escape the string so it's safe to use in XML and xpath. + """ + entities = { + '"': """, + "'": "'", + } + if isinstance(string, bytes): + return xml.sax.saxutils.escape(string.decode("utf-8"), entities=entities).encode("utf-8") + return xml.sax.saxutils.escape(string, entities=entities) + + +def xml_unescape(string): + """ + Decode XML entities in the string. + """ + entities = { + """: '"', + "'": "'", + } + if isinstance(string, bytes): + return xml.sax.saxutils.unescape(string.decode("utf-8"), entities=entities).encode("utf-8") + return xml.sax.saxutils.unescape(string, entities=entities) + + +def xml_strip_text(node): + """ + Recursively strip inner text in nodes: + - if text contains only whitespaces + - if node contains child nodes + """ + if node.text and not node.text.strip(): + node.text = None + elif len(node) != 0: + node.text = None + for child in node: + xml_strip_text(child) + + +def xml_indent_compat(elem, level=0): + """ + XML indentation code for python < 3.9. + Source: http://effbot.org/zone/element-lib.htm#prettyprint + """ + i = "\n" + level * " " + if isinstance(elem, ET.ElementTree): + elem = elem.getroot() + if len(elem): + if not elem.text or not elem.text.strip(): + elem.text = i + " " + for e in elem: + xml_indent_compat(e, level + 1) + if not e.tail or not e.tail.strip(): + e.tail = i + " " + if not e.tail or not e.tail.strip(): + e.tail = i + else: + if level and (not elem.tail or not elem.tail.strip()): + elem.tail = i + + +def xml_indent(root): + """ + Indent XML so it looks pretty after printing or saving to file. + """ + if hasattr(ET, "indent"): + # ElementTree supports indent() in Python 3.9 and newer + xml_strip_text(root) + ET.indent(root) + else: + xml_indent_compat(root)