File: util_xml.py

package info (click to toggle)
displaycal-py3 3.9.16-1
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 29,120 kB
  • sloc: python: 115,777; javascript: 11,540; xml: 598; sh: 257; makefile: 173
file content (107 lines) | stat: -rw-r--r-- 3,194 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# -*- coding: utf-8 -*-

try:
    from xml.etree import ElementTree as ET
except ImportError:
    pass


def dict2xml(d, elementname="element", pretty=True, allow_attributes=True, level=0):
    indent = pretty and "\t" * level or ""
    xml = []
    attributes = []
    children = []

    if isinstance(d, (dict, list)):
        start_tag = []
        start_tag.append(indent + "<" + elementname)

        if isinstance(d, dict):
            for key in d:
                value = d[key]
                if isinstance(value, (dict, list)) or not allow_attributes:
                    children.append(
                        dict2xml(value, key, pretty, allow_attributes, level + 1)
                    )
                else:
                    if pretty:
                        attributes.append("\n" + indent)
                    attributes.append(' %s="%s"' % (key, escape(str(value))))
        else:
            for value in d:
                children.append(
                    dict2xml(value, "item", pretty, allow_attributes, level + 1)
                )

        start_tag.extend(attributes)
        start_tag.append(children and ">" or "/>")
        xml.append("".join(start_tag))

        if children:
            for child in children:
                xml.append(child)

            xml.append("%s</%s>" % (indent, elementname))
    else:
        xml.append("%s<%s>%s</%s>" % (indent, elementname, escape(str(d)), elementname))

    return (pretty and "\n" or "").join(xml)


def escape(xml):
    return (
        xml.replace("&", "&amp;")
        .replace("<", "&lt;")
        .replace(">", "&gt;")
        .replace('"', "&quot;")
    )


class ETreeDict(dict):
    # Roughly follow "Converting Between XML and JSON"
    # https://www.xml.com/pub/a/2006/05/31/converting-between-xml-and-json.html

    def __init__(self, etree):
        super(ETreeDict, self).__init__()
        children = len(etree)
        if etree.attrib or etree.text or children:
            self[etree.tag] = dict(("@" + k, v) for k, v in etree.attrib.items())
            if etree.text:
                text = etree.text.strip()
                if etree.attrib or children:
                    if text:
                        self[etree.tag]["#text"] = text
                else:
                    self[etree.tag] = text
            if children:
                d = self[etree.tag]
                for child in etree:
                    for k, v in ETreeDict(child).items():
                        if k in d:
                            if not isinstance(d[k], list):
                                d[k] = [d[k]]
                            d[k].append(v)
                        else:
                            d[k] = v
        else:
            self[etree.tag] = None

    def __repr__(self):
        """od.__repr__() <==> repr(od)"""
        l = []
        for k in self:
            v = self[k]
            l.append("%r: %r" % (k, v))
        return "{%s}" % ", ".join(l)

    @property
    def json(self):
        import json

        return json.dumps(self)


class XMLDict(ETreeDict):
    def __init__(self, xml):
        etree = ET.fromstring(xml)
        ETreeDict.__init__(self, etree)