From 00dc60beee3bf4b68fd658716616f25503a3a9eb Mon Sep 17 00:00:00 2001
From: Ezio Melotti
Date: Fri, 18 Nov 2011 18:00:40 +0200
Subject: [PATCH] #13358: HTMLParser now calls handle_data only once for each
CDATA.
---
Lib/HTMLParser.py | 7 ++++---
Lib/test/test_htmlparser.py | 21 +++++++++++++++++++++
Misc/NEWS | 2 ++
3 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/Lib/HTMLParser.py b/Lib/HTMLParser.py
index cd353f8ca03..1c6989e7d44 100644
--- a/Lib/HTMLParser.py
+++ b/Lib/HTMLParser.py
@@ -14,7 +14,6 @@ import re
# Regular expressions used for parsing
interesting_normal = re.compile('[&<]')
-interesting_cdata = re.compile(r'<(/|\Z)')
incomplete = re.compile('&[a-zA-Z#]')
entityref = re.compile('&([a-zA-Z][-.a-zA-Z0-9]*)[^a-zA-Z0-9]')
@@ -125,8 +124,8 @@ class HTMLParser(markupbase.ParserBase):
return self.__starttag_text
def set_cdata_mode(self, elem):
- self.interesting = interesting_cdata
self.cdata_elem = elem.lower()
+ self.interesting = re.compile(r'\s*%s\s*>' % self.cdata_elem, re.I)
def clear_cdata_mode(self):
self.interesting = interesting_normal
@@ -144,6 +143,8 @@ class HTMLParser(markupbase.ParserBase):
if match:
j = match.start()
else:
+ if self.cdata_elem:
+ break
j = n
if i < j: self.handle_data(rawdata[i:j])
i = self.updatepos(i, j)
@@ -212,7 +213,7 @@ class HTMLParser(markupbase.ParserBase):
else:
assert 0, "interesting.search() lied"
# end while
- if end and i < n:
+ if end and i < n and not self.cdata_elem:
self.handle_data(rawdata[i:n])
i = self.updatepos(i, n)
self.rawdata = rawdata[i:]
diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py
index b84e7dc935f..5dfe466225e 100644
--- a/Lib/test/test_htmlparser.py
+++ b/Lib/test/test_htmlparser.py
@@ -286,6 +286,27 @@ DOCTYPE html [
("data", content),
("endtag", element_lower)])
+ def test_cdata_with_closing_tags(self):
+ # see issue #13358
+ # make sure that HTMLParser calls handle_data only once for each CDATA.
+ # The normal event collector normalizes the events in get_events,
+ # so we override it to return the original list of events.
+ class Collector(EventCollector):
+ def get_events(self):
+ return self.events
+
+ content = """ ¬-an-entity-ref;
+
&
+ ''