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

1"""XmlElement implementation.""" 

2 

3import xml.etree.ElementTree 

4 

5import gws 

6 

7from . import namespace, serializer 

8 

9 

10class XmlElementImpl(xml.etree.ElementTree.Element, gws.XmlElement): 

11 

12 def __init__(self, tag, attrib=None, **extra): 

13 xml.etree.ElementTree.Element.__init__(self, tag, attrib or {}, **extra) 

14 

15 self.text = self.text or '' 

16 self.tail = self.tail or '' 

17 

18 _, _, pname = namespace.split_name(tag) 

19 self.name = pname 

20 self.lcName = pname.lower() 

21 

22 self.caseInsensitive = False 

23 

24 def __bool__(self): 

25 return True 

26 

27 def __iter__(self): 

28 for i in range(len(self)): 

29 yield self[i] 

30 

31 def find(self, path, namespaces=None): 

32 return super().find(self._convert_path(path), namespaces) 

33 

34 def findtext(self, path, default=None, namespaces=None): 

35 return super().findtext(self._convert_path(path), default, namespaces) 

36 

37 def findall(self, path, namespaces=None): 

38 return super().findall(self._convert_path(path), namespaces) 

39 

40 def iterfind(self, path, namespaces=None): 

41 return super().iterfind(self._convert_path(path), namespaces) 

42 

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 

52 

53 def iter(self, tag=None): 

54 return super().iter(self._convert_path(tag)) 

55 

56 ## 

57 

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 } 

66 

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 ) 

73 

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 ) 

92 

93 ## 

94 

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 

100 

101 def attr(self, key, default=None): 

102 return self.get(key, default) 

103 

104 def children(self): 

105 return [c for c in self] 

106 

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 

114 

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 

120 

121 def textlist(self, *paths, deep=False): 

122 buf = self._collect_text(paths, deep) 

123 return [text for _, text in buf] 

124 

125 def textdict(self, *paths, deep=False): 

126 buf = self._collect_text(paths, deep) 

127 return dict(buf) 

128 

129 ## 

130 

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) 

139 

140 buf = [] 

141 

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) 

149 

150 return buf 

151 

152 def _convert_path(self, path): 

153 if self.caseInsensitive: 

154 path = path.lower() 

155 return path 

156 

157 def _convert_key(self, key): 

158 if self.caseInsensitive: 

159 key = key.lower() 

160 return key 

161