Skip to content

Commit 00dc60b

Browse files
committed
#13358: HTMLParser now calls handle_data only once for each CDATA.
1 parent 93bbb6a commit 00dc60b

3 files changed

Lines changed: 27 additions & 3 deletions

File tree

Lib/HTMLParser.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
# Regular expressions used for parsing
1515

1616
interesting_normal = re.compile('[&<]')
17-
interesting_cdata = re.compile(r'<(/|\Z)')
1817
incomplete = re.compile('&[a-zA-Z#]')
1918

2019
entityref = re.compile('&([a-zA-Z][-.a-zA-Z0-9]*)[^a-zA-Z0-9]')
@@ -125,8 +124,8 @@ def get_starttag_text(self):
125124
return self.__starttag_text
126125

127126
def set_cdata_mode(self, elem):
128-
self.interesting = interesting_cdata
129127
self.cdata_elem = elem.lower()
128+
self.interesting = re.compile(r'</\s*%s\s*>' % self.cdata_elem, re.I)
130129

131130
def clear_cdata_mode(self):
132131
self.interesting = interesting_normal
@@ -144,6 +143,8 @@ def goahead(self, end):
144143
if match:
145144
j = match.start()
146145
else:
146+
if self.cdata_elem:
147+
break
147148
j = n
148149
if i < j: self.handle_data(rawdata[i:j])
149150
i = self.updatepos(i, j)
@@ -212,7 +213,7 @@ def goahead(self, end):
212213
else:
213214
assert 0, "interesting.search() lied"
214215
# end while
215-
if end and i < n:
216+
if end and i < n and not self.cdata_elem:
216217
self.handle_data(rawdata[i:n])
217218
i = self.updatepos(i, n)
218219
self.rawdata = rawdata[i:]

Lib/test/test_htmlparser.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,27 @@ def test_cdata_content(self):
286286
("data", content),
287287
("endtag", element_lower)])
288288

289+
def test_cdata_with_closing_tags(self):
290+
# see issue #13358
291+
# make sure that HTMLParser calls handle_data only once for each CDATA.
292+
# The normal event collector normalizes the events in get_events,
293+
# so we override it to return the original list of events.
294+
class Collector(EventCollector):
295+
def get_events(self):
296+
return self.events
297+
298+
content = """<!-- not a comment --> &not-an-entity-ref;
299+
<a href="" /> </p><p> &amp; <span></span></style>
300+
'</script' + '>' </html> </head> </scripter>!"""
301+
for element in [' script', 'script ', ' script ',
302+
'\nscript', 'script\n', '\nscript\n']:
303+
s = u'<script>{content}</{element}>'.format(element=element,
304+
content=content)
305+
self._run_check(s, [("starttag", "script", []),
306+
("data", content),
307+
("endtag", "script")],
308+
collector=Collector)
309+
289310
def test_malformatted_charref(self):
290311
self._run_check("<p>&#bad;</p>", [
291312
("starttag", "p", []),

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ Core and Builtins
7979
Library
8080
-------
8181

82+
- Issue #13358: HTMLParser now calls handle_data only once for each CDATA.
83+
8284
- Issue #4147: minidom's toprettyxml no longer adds whitespace around a text
8385
node when it is the only child of an element. Initial patch by Dan
8486
Kenigsberg.

0 commit comments

Comments
 (0)