Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions Lib/test/test_minidom.py
Original file line number Diff line number Diff line change
Expand Up @@ -1784,5 +1784,38 @@ def test_cdata_parsing(self):
dom2 = parseString(dom1.toprettyxml())
self.checkWholeText(dom2.getElementsByTagName('node')[0].firstChild, '</data>')

def test_notation_decl_filter(self):
# gh-152142: a DOMBuilderFilter accepting a notation must keep it and
# rejecting it must drop it, matching entity declarations.
from xml.dom.expatbuilder import makeBuilder
from xml.dom.xmlbuilder import DOMBuilderFilter, Options

source = (b'<?xml version="1.0"?>\n'
b'<!DOCTYPE root [\n'
b' <!NOTATION gif PUBLIC "image/gif">\n'
b' <!ENTITY logo SYSTEM "logo.gif" NDATA gif>\n'
b']>\n'
b'<root/>')

class Filter(DOMBuilderFilter):
def __init__(self, result):
self.result = result
def acceptNode(self, node):
if node.nodeType == Node.NOTATION_NODE:
return self.result
return self.FILTER_ACCEPT

def counts(filt):
options = Options()
options.filter = filt
doctype = makeBuilder(options).parseFile(io.BytesIO(source)).doctype
return doctype.notations.length, doctype.entities.length

# The entity must stay untouched in every case; only the notation
# follows the filter result.
self.assertEqual(counts(None), (1, 1))
self.assertEqual(counts(Filter(DOMBuilderFilter.FILTER_ACCEPT)), (1, 1))
self.assertEqual(counts(Filter(DOMBuilderFilter.FILTER_REJECT)), (0, 1))

if __name__ == "__main__":
unittest.main()
2 changes: 1 addition & 1 deletion Lib/xml/dom/expatbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ def entity_decl_handler(self, entityName, is_parameter_entity, value,
def notation_decl_handler(self, notationName, base, systemId, publicId):
node = self.document._create_notation(notationName, publicId, systemId)
self.document.doctype.notations._seq.append(node)
if self._filter and self._filter.acceptNode(node) == FILTER_ACCEPT:
if self._filter and self._filter.acceptNode(node) == FILTER_REJECT:
del self.document.doctype.notations._seq[-1]

def comment_handler(self, data):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fix the handling of notation declarations by
:class:`!xml.dom.xmlbuilder.DOMBuilderFilter` in :mod:`xml.dom.minidom`. A
notation that the filter accepted was dropped and a rejected one was kept, the
opposite of the filter contract and of entity declarations.
Loading