Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f802d2d

Browse files
gh-157406: Report all document type declarations in the Python XMLParser (GH-157408)
The Python implementation of XMLParser only reported a document type declaration with an external identifier. Use the Expat handler, like the C implementation does.
1 parent fde6296 commit f802d2d

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
@@ -4211,6 +4211,21 @@ def close(self):
42114211
('html', '-//W3C//DTD XHTML 1.0 Transitional//EN',
42124212
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'))
42134213

4214+
for doctype, expected in [
4215+
('<!DOCTYPE html>', ('html', None, None)),
4216+
('<!DOCTYPE html [<!ENTITY e "v">]>', ('html', None, None)),
4217+
('<!DOCTYPE html SYSTEM "a.dtd">', ('html', None, 'a.dtd')),
4218+
('<!DOCTYPE html SYSTEM "a.dtd" [<!ENTITY e "v">]>',
4219+
('html', None, 'a.dtd')),
4220+
('<!DOCTYPE html PUBLIC "-//P" "a.dtd">', ('html', '-//P', 'a.dtd')),
4221+
("<!DOCTYPE\nhtml\nPUBLIC\n'-//P'\n'a.dtd'\n>",
4222+
('html', '-//P', 'a.dtd')),
4223+
]:
4224+
with self.subTest(doctype=doctype):
4225+
parser = ET.XMLParser(target=DoctypeParser())
4226+
parser.feed(doctype + '<html/>')
4227+
self.assertEqual(parser.close(), expected)
4228+
42144229
def test_builder_lookup_errors(self):
42154230
class RaisingBuilder:
42164231
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
@@ -1591,10 +1591,10 @@ def __init__(self, *, target=None, encoding=None):
15911591
parser.CommentHandler = target.comment
15921592
if hasattr(target, 'pi'):
15931593
parser.ProcessingInstructionHandler = target.pi
1594+
parser.StartDoctypeDeclHandler = self._start_doctype
15941595
# Configure pyexpat: buffering, new-style attribute handling.
15951596
parser.buffer_text = 1
15961597
parser.ordered_attributes = 1
1597-
self._doctype = None
15981598
self.entity = {}
15991599
try:
16001600
self.version = "Expat %d.%d.%d" % expat.version_info
@@ -1713,38 +1713,15 @@ def _default(self, text):
17131713
err.lineno = self.parser.ErrorLineNumber
17141714
err.offset = self.parser.ErrorColumnNumber
17151715
raise err
1716-
elif prefix == "<" and text[:9] == "<!DOCTYPE":
1717-
self._doctype = [] # inside a doctype declaration
1718-
elif self._doctype is not None:
1719-
# parse doctype contents
1720-
if prefix == ">":
1721-
self._doctype = None
1722-
return
1723-
text = text.strip(_XML_WHITESPACE)
1724-
if not text:
1725-
return
1726-
self._doctype.append(text)
1727-
n = len(self._doctype)
1728-
if n > 2:
1729-
type = self._doctype[1]
1730-
if type == "PUBLIC" and n == 4:
1731-
name, type, pubid, system = self._doctype
1732-
if pubid:
1733-
pubid = pubid[1:-1]
1734-
elif type == "SYSTEM" and n == 3:
1735-
name, type, system = self._doctype
1736-
pubid = None
1737-
else:
1738-
return
1739-
if hasattr(self.target, "doctype"):
1740-
self.target.doctype(name, pubid, system[1:-1])
1741-
elif hasattr(self, "doctype"):
1742-
warnings.warn(
1743-
"The doctype() method of XMLParser is ignored. "
1744-
"Define doctype() method on the TreeBuilder target.",
1745-
RuntimeWarning)
1746-
1747-
self._doctype = None
1716+
1717+
def _start_doctype(self, name, system, pubid, has_internal_subset):
1718+
if hasattr(self.target, "doctype"):
1719+
self.target.doctype(name, pubid, system)
1720+
elif hasattr(self, "doctype"):
1721+
warnings.warn(
1722+
"The doctype() method of XMLParser is ignored. "
1723+
"Define doctype() method on the TreeBuilder target.",
1724+
RuntimeWarning)
17481725

17491726
def feed(self, data):
17501727
"""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)