16
16
import re
17
17
import sys
18
18
19
+ try :
20
+ from collections .abc import MutableMapping
21
+ except ImportError :
22
+ from collections import MutableMapping
23
+
19
24
from . import base
20
25
from ..constants import DataLossWarning
21
26
from .. import constants
22
27
from . import etree as etree_builders
23
28
from .. import _ihatexml
24
29
25
30
import lxml .etree as etree
31
+ from six import PY3 , binary_type
26
32
27
33
28
34
fullTree = True
@@ -189,26 +195,37 @@ def __init__(self, namespaceHTMLElements, fullTree=False):
189
195
infosetFilter = self .infosetFilter = _ihatexml .InfosetFilter (preventDoubleDashComments = True )
190
196
self .namespaceHTMLElements = namespaceHTMLElements
191
197
192
- class Attributes (dict ):
193
- def __init__ (self , element , value = None ):
194
- if value is None :
195
- value = {}
198
+ class Attributes (MutableMapping ):
199
+ def __init__ (self , element ):
196
200
self ._element = element
197
- dict .__init__ (self , value ) # pylint:disable=non-parent-init-called
198
- for key , value in self .items ():
199
- if isinstance (key , tuple ):
200
- name = "{%s}%s" % (key [2 ], infosetFilter .coerceAttribute (key [1 ]))
201
- else :
202
- name = infosetFilter .coerceAttribute (key )
203
- self ._element ._element .attrib [name ] = value
204
201
205
- def __setitem__ (self , key , value ):
206
- dict .__setitem__ (self , key , value )
202
+ def _coerceKey (self , key ):
207
203
if isinstance (key , tuple ):
208
204
name = "{%s}%s" % (key [2 ], infosetFilter .coerceAttribute (key [1 ]))
209
205
else :
210
206
name = infosetFilter .coerceAttribute (key )
211
- self ._element ._element .attrib [name ] = value
207
+ return name
208
+
209
+ def __getitem__ (self , key ):
210
+ value = self ._element ._element .attrib [self ._coerceKey (key )]
211
+ if not PY3 and isinstance (value , binary_type ):
212
+ value = value .decode ("ascii" )
213
+ return value
214
+
215
+ def __setitem__ (self , key , value ):
216
+ self ._element ._element .attrib [self ._coerceKey (key )] = value
217
+
218
+ def __delitem__ (self , key ):
219
+ del self ._element ._element .attrib [self ._coerceKey (key )]
220
+
221
+ def __iter__ (self ):
222
+ return iter (self ._element ._element .attrib )
223
+
224
+ def __len__ (self ):
225
+ return len (self ._element ._element .attrib )
226
+
227
+ def clear (self ):
228
+ return self ._element ._element .attrib .clear ()
212
229
213
230
class Element (builder .Element ):
214
231
def __init__ (self , name , namespace ):
@@ -229,17 +246,22 @@ def _getName(self):
229
246
def _getAttributes (self ):
230
247
return self ._attributes
231
248
232
- def _setAttributes (self , attributes ):
233
- self ._attributes = Attributes (self , attributes )
249
+ def _setAttributes (self , value ):
250
+ attributes = self .attributes
251
+ attributes .clear ()
252
+ attributes .update (value )
234
253
235
254
attributes = property (_getAttributes , _setAttributes )
236
255
237
256
def insertText (self , data , insertBefore = None ):
238
257
data = infosetFilter .coerceCharacters (data )
239
258
builder .Element .insertText (self , data , insertBefore )
240
259
241
- def appendChild (self , child ):
242
- builder .Element .appendChild (self , child )
260
+ def cloneNode (self ):
261
+ element = type (self )(self .name , self .namespace )
262
+ if self ._element .attrib :
263
+ element ._element .attrib .update (self ._element .attrib )
264
+ return element
243
265
244
266
class Comment (builder .Comment ):
245
267
def __init__ (self , data ):
0 commit comments