From 89f49dceeb844b78e354ef8a54a17a3ef02b17a7 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Sun, 7 Apr 2019 03:30:31 +0200 Subject: [PATCH 09/10] add utils to access XML data from expression (#31595) --- passerelle/utils/xml.py | 33 +++++++++++++++++++++++++++++++++ tests/test_utils_xml.py | 23 ++++++++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/passerelle/utils/xml.py b/passerelle/utils/xml.py index ebe9213a..2a24ad01 100644 --- a/passerelle/utils/xml.py +++ b/passerelle/utils/xml.py @@ -14,6 +14,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from django.utils import six + def text_content(node): '''Extract text content from node and all its children. Equivalent to @@ -81,3 +83,34 @@ def to_json(root): if child_content: d[child.tag].append(child_content) return d + + +@six.python_2_unicode_compatible +class XMLAccessor(object): + def __init__(self, root): + self.root = root + + def __getattr__(self, name): + def helper(): + for child in self.root: + localname = child.tag.rsplit('}', 1)[-1] + if localname == name: + yield child + children = list(helper()) + if len(children) == 0: + return None + elif len(children) > 1: + raise Exception('too many children named %s' % name) + else: + return XMLAccessor(children[0]) + + def __str__(self): + if len(self.root) == 0: + return text_content(self.root) + else: + return '' + + +def add_xml_accessor(d, root): + localname = root.tag.rsplit('}', 1)[-1] + d[localname] = XMLAccessor(root) diff --git a/tests/test_utils_xml.py b/tests/test_utils_xml.py index 9dd5d66b..d9e43adb 100644 --- a/tests/test_utils_xml.py +++ b/tests/test_utils_xml.py @@ -1,6 +1,8 @@ import xml.etree.ElementTree as ET -from passerelle.utils.xml import to_json, text_content +from django.utils import six + +from passerelle.utils.xml import to_json, text_content, XMLAccessor, add_xml_accessor def test_text_content(): @@ -31,3 +33,22 @@ def test_to_json(): {'text3': '4'}, ] } + + +def test_xml_accessor(): + root = ET.fromstring(''' + 1 + 2 + + + 4 + + + + +''') + d = {} + add_xml_accessor(d, root) + assert d['root'] + assert six.text_type(d['root'].text1) == '1' + assert six.text_type(d['root'].enfants.enfant.text3) == '4' -- 2.20.1