@@ -25,19 +25,35 @@ class Element(_base.Node):
25
25
def __init__ (self , element , soup ):
26
26
_base .Node .__init__ (self , element .name )
27
27
self .element = element
28
- self .soup = soup
28
+ self .soup = soup
29
+
30
+ def _nodeIndex (self , node , refNode ):
31
+ # Finds a node by identity rather than equality
32
+ for index in range (len (self .element .contents )):
33
+ if id (self .element .contents [index ]) == id (refNode .element ):
34
+ return index
35
+ return None
29
36
30
37
def appendChild (self , node ):
31
38
if (node .element .__class__ == NavigableString and self .element .contents
32
39
and self .element .contents [- 1 ].__class__ == NavigableString ):
33
- newNode = TextNode (NavigableString (
34
- self .element .contents [- 1 ]+ node .element ), self .soup )
35
- self .element .contents [- 1 ].extract ()
36
- self .appendChild (newNode )
40
+ # Concatenate new text onto old text node
41
+ # (TODO: This has O(n^2) performance, for input like "a</a>a</a>a</a>...")
42
+ newStr = NavigableString (self .element .contents [- 1 ]+ node .element )
43
+
44
+ # Remove the old text node
45
+ # (Can't simply use .extract() by itself, because it fails if
46
+ # an equal text node exists within the parent node)
47
+ oldElement = self .element .contents [- 1 ]
48
+ del self .element .contents [- 1 ]
49
+ oldElement .parent = None
50
+ oldElement .extract ()
51
+
52
+ self .element .insert (len (self .element .contents ), newStr )
37
53
else :
38
54
self .element .insert (len (self .element .contents ), node .element )
39
55
node .parent = self
40
-
56
+
41
57
def getAttributes (self ):
42
58
return AttrList (self .element )
43
59
@@ -56,18 +72,25 @@ def insertText(self, data, insertBefore=None):
56
72
self .appendChild (text )
57
73
58
74
def insertBefore (self , node , refNode ):
59
- index = self .element . contents . index ( refNode . element )
75
+ index = self ._nodeIndex ( node , refNode )
60
76
if (node .element .__class__ == NavigableString and self .element .contents
61
77
and self .element .contents [index - 1 ].__class__ == NavigableString ):
62
- newNode = TextNode (NavigableString (
63
- self .element .contents [index - 1 ]+ node .element ), self .soup )
64
- self .element .contents [index - 1 ].extract ()
65
- self .insertBefore (newNode , refNode )
78
+ # (See comments in appendChild)
79
+ newStr = NavigableString (self .element .contents [index - 1 ]+ node .element )
80
+ oldNode = self .element .contents [index - 1 ]
81
+ del self .element .contents [index - 1 ]
82
+ oldNode .parent = None
83
+ oldNode .extract ()
84
+
85
+ self .element .insert (index - 1 , newStr )
66
86
else :
67
87
self .element .insert (index , node .element )
68
88
node .parent = self
69
89
70
90
def removeChild (self , node ):
91
+ index = self ._nodeIndex (node .parent , node )
92
+ del node .parent .element .contents [index ]
93
+ node .element .parent = None
71
94
node .element .extract ()
72
95
node .parent = None
73
96
@@ -93,7 +116,7 @@ class TextNode(Element):
93
116
def __init__ (self , element , soup ):
94
117
_base .Node .__init__ (self , None )
95
118
self .element = element
96
- self .soup = soup
119
+ self .soup = soup
97
120
98
121
def cloneNode (self ):
99
122
raise NotImplementedError
0 commit comments