Skip to content

Commit e7e092b

Browse files
[3.14] gh-157406: Report all document type declarations in the Python XMLParser (GH-157408) (GH-157409)
The Python implementation of XMLParser only reported a document type declaration with an external identifier. Use the Expat handler, like the C implementation does. (cherry picked from commit f802d2d) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent a8d8774 commit e7e092b

3 files changed

Lines changed: 29 additions & 33 deletions

File tree

Lib/test/test_xml_etree.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4002,6 +4002,21 @@ def close(self):
40024002
('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
40034003
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
40044004

4005+
for doctype, expected in [
4006+
('<!DOCTYPE html>', ('html', None, None)),
4007+
('<!DOCTYPE html [<!ENTITY e "v">]>', ('html', None, None)),
4008+
('<!DOCTYPE html SYSTEM "a.dtd">', ('html', None, 'a.dtd')),
4009+
('<!DOCTYPE html SYSTEM "a.dtd" [<!ENTITY e "v">]>',
4010+
('html', None, 'a.dtd')),
4011+
('<!DOCTYPE html PUBLIC "-//P" "a.dtd">', ('html', '-//P', 'a.dtd')),
4012+
("<!DOCTYPE\nhtml\nPUBLIC\n'-//P'\n'a.dtd'\n>",
4013+
('html', '-//P', 'a.dtd')),
4014+
]:
4015+
with self.subTest(doctype=doctype):
4016+
parser = ET.XMLParser(target=DoctypeParser())
4017+
parser.feed(doctype + '<html/>')
4018+
self.assertEqual(parser.close(), expected)
4019+
40054020
def test_builder_lookup_errors(self):
40064021
class RaisingBuilder:
40074022
def __init__(self, raise_in=None, what=ValueError):

Lib/xml/etree/ElementTree.py

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,10 +1572,10 @@ def __init__(self, *, target=None, encoding=None):
15721572
parser.CommentHandler = target.comment
15731573
if hasattr(target, 'pi'):
15741574
parser.ProcessingInstructionHandler = target.pi
1575+
parser.StartDoctypeDeclHandler = self._start_doctype
15751576
# Configure pyexpat: buffering, new-style attribute handling.
15761577
parser.buffer_text = 1
15771578
parser.ordered_attributes = 1
1578-
self._doctype = None
15791579
self.entity = {}
15801580
try:
15811581
self.version = "Expat %d.%d.%d" % expat.version_info
@@ -1694,38 +1694,15 @@ def _default(self, text):
16941694
err.lineno = self.parser.ErrorLineNumber
16951695
err.offset = self.parser.ErrorColumnNumber
16961696
raise err
1697-
elif prefix == "<" and text[:9] == "<!DOCTYPE":
1698-
self._doctype = [] # inside a doctype declaration
1699-
elif self._doctype is not None:
1700-
# parse doctype contents
1701-
if prefix == ">":
1702-
self._doctype = None
1703-
return
1704-
text = text.strip(_XML_WHITESPACE)
1705-
if not text:
1706-
return
1707-
self._doctype.append(text)
1708-
n = len(self._doctype)
1709-
if n > 2:
1710-
type = self._doctype[1]
1711-
if type == "PUBLIC" and n == 4:
1712-
name, type, pubid, system = self._doctype
1713-
if pubid:
1714-
pubid = pubid[1:-1]
1715-
elif type == "SYSTEM" and n == 3:
1716-
name, type, system = self._doctype
1717-
pubid = None
1718-
else:
1719-
return
1720-
if hasattr(self.target, "doctype"):
1721-
self.target.doctype(name, pubid, system[1:-1])
1722-
elif hasattr(self, "doctype"):
1723-
warnings.warn(
1724-
"The doctype() method of XMLParser is ignored. "
1725-
"Define doctype() method on the TreeBuilder target.",
1726-
RuntimeWarning)
1727-
1728-
self._doctype = None
1697+
1698+
def _start_doctype(self, name, system, pubid, has_internal_subset):
1699+
if hasattr(self.target, "doctype"):
1700+
self.target.doctype(name, pubid, system)
1701+
elif hasattr(self, "doctype"):
1702+
warnings.warn(
1703+
"The doctype() method of XMLParser is ignored. "
1704+
"Define doctype() method on the TreeBuilder target.",
1705+
RuntimeWarning)
17291706

17301707
def feed(self, data):
17311708
"""Feed encoded data to parser."""
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fix the Python implementation of :class:`xml.etree.ElementTree.XMLParser`:
2+
the ``doctype()`` method of the target is now called for a document type
3+
declaration without an external identifier, like ``<!DOCTYPE html>``,
4+
as in the C implementation.

0 commit comments

Comments
 (0)