Coverage for gws-app/gws/lib/xmlx/element.py: 85%
93 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
1"""XmlElement implementation."""
3import xml.etree.ElementTree
5import gws
7from . import namespace, serializer
10class XmlElementImpl(xml.etree.ElementTree.Element, gws.XmlElement):
12 def __init__(self, tag, attrib=None, **extra):
13 xml.etree.ElementTree.Element.__init__(self, tag, attrib or {}, **extra)
15 self.text = self.text or ''
16 self.tail = self.tail or ''
18 _, _, pname = namespace.split_name(tag)
19 self.name = pname
20 self.lcName = pname.lower()
22 self.caseInsensitive = False
24 def __bool__(self):
25 return True
27 def __iter__(self):
28 for i in range(len(self)):
29 yield self[i]
31 def find(self, path, namespaces=None):
32 return super().find(self._convert_path(path), namespaces)
34 def findtext(self, path, default=None, namespaces=None):
35 return super().findtext(self._convert_path(path), default, namespaces)
37 def findall(self, path, namespaces=None):
38 return super().findall(self._convert_path(path), namespaces)
40 def iterfind(self, path, namespaces=None):
41 return super().iterfind(self._convert_path(path), namespaces)
43 def get(self, key, default=None):
44 if self.caseInsensitive:
45 key = key.lower()
46 if key in self.attrib:
47 return self.attrib[key]
48 for k, v in self.attrib.items():
49 if namespace.unqualify_name(k) == key:
50 return v
51 return default
53 def iter(self, tag=None):
54 return super().iter(self._convert_path(tag))
56 ##
58 def to_dict(self):
59 return {
60 'tag': self.tag,
61 'attrib': self.attrib,
62 'text': self.text,
63 'tail': self.tail,
64 'children': [c.to_dict() for c in self.children()]
65 }
67 def to_list(self, fold_tags=True, remove_namespaces=False):
68 return serializer.to_list(
69 self,
70 fold_tags=fold_tags,
71 remove_namespaces=remove_namespaces,
72 )
74 def to_string(
75 self,
76 extra_namespaces=None,
77 compact_whitespace=False,
78 remove_namespaces=False,
79 with_namespace_declarations=False,
80 with_schema_locations=False,
81 with_xml_declaration=False,
82 ):
83 return serializer.to_string(
84 self,
85 extra_namespaces=extra_namespaces,
86 compact_whitespace=compact_whitespace,
87 remove_namespaces=remove_namespaces,
88 with_namespace_declarations=with_namespace_declarations,
89 with_schema_locations=with_schema_locations,
90 with_xml_declaration=with_xml_declaration,
91 )
93 ##
95 def add(self, tag, attrib=None, **extra):
96 el = self.__class__(tag, attrib, **extra)
97 el.caseInsensitive = self.caseInsensitive
98 self.append(el)
99 return el
101 def attr(self, key, default=None):
102 return self.get(key, default)
104 def children(self):
105 return [c for c in self]
107 def findfirst(self, *paths):
108 if not paths:
109 return self[0] if len(self) > 0 else None
110 for path in paths:
111 el = self.find(path)
112 if el is not None:
113 return el
115 def textof(self, *paths):
116 for path in paths:
117 el = self.find(path)
118 if el is not None and el.text:
119 return el.text
121 def textlist(self, *paths, deep=False):
122 buf = self._collect_text(paths, deep)
123 return [text for _, text in buf]
125 def textdict(self, *paths, deep=False):
126 buf = self._collect_text(paths, deep)
127 return dict(buf)
129 ##
131 def _collect_text(self, paths, deep):
132 def walk(el):
133 s = (el.text or '').strip()
134 if s:
135 buf.append((el.tag, s))
136 if deep:
137 for c in el:
138 walk(c)
140 buf = []
142 if not paths:
143 for el in self:
144 walk(el)
145 else:
146 for path in paths:
147 for el in self.findall(path):
148 walk(el)
150 return buf
152 def _convert_path(self, path):
153 if self.caseInsensitive:
154 path = path.lower()
155 return path
157 def _convert_key(self, key):
158 if self.caseInsensitive:
159 key = key.lower()
160 return key