diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 4882ddb4310fc2..f70c2e5d36b1f9 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -824,6 +824,9 @@ xml.parsers.expat .. _billion laughs: https://en.wikipedia.org/wiki/Billion_laughs_attack +* Add support for `namespace prefixes `_. + (Contributed by Yassir Karroum in :gh:`118317`.) + zlib ---- diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py index 5c10bcedc69bc6..46975e351b42f9 100644 --- a/Lib/test/test_sax.py +++ b/Lib/test/test_sax.py @@ -1,7 +1,6 @@ # regression test for SAX 2.0 - from xml.sax import make_parser, ContentHandler, \ - SAXException, SAXReaderNotAvailable, SAXParseException + SAXException, SAXReaderNotAvailable, SAXParseException, handler import unittest from unittest import mock try: @@ -1307,6 +1306,23 @@ def test_expat_locator_withinfo_nonascii(self): self.assertEqual(parser.getSystemId(), fname) self.assertEqual(parser.getPublicId(), None) + def test_qualified_names(self): + + class Handler(ContentHandler): + def startElementNS(self, name, qname, attrs): + self.qname = qname + + for xml_s, expected_qname in zip(["", "", ""], ["Q:E", "E", "E"]): + parser = create_parser() + parser.setFeature(handler.feature_namespaces, 1) + parser.setFeature(handler.feature_namespace_prefixes, 1) + + h = Handler() + + parser.setContentHandler(h) + parser.parse(StringIO(xml_s)) + self.assertEqual(h.qname, expected_qname) + # =========================================================================== # diff --git a/Lib/xml/sax/expatreader.py b/Lib/xml/sax/expatreader.py index ba3c1e98517429..0388f2c5cdc7b9 100644 --- a/Lib/xml/sax/expatreader.py +++ b/Lib/xml/sax/expatreader.py @@ -81,7 +81,7 @@ def getSystemId(self): class ExpatParser(xmlreader.IncrementalParser, xmlreader.Locator): """SAX driver for the pyexpat C module.""" - def __init__(self, namespaceHandling=0, bufsize=2**16-20): + def __init__(self, namespaceHandling=0, namespacePrefixesHandling=0, bufsize=2**16-20): xmlreader.IncrementalParser.__init__(self, bufsize) self._source = xmlreader.InputSource() self._parser = None @@ -91,6 +91,7 @@ def __init__(self, namespaceHandling=0, bufsize=2**16-20): self._entity_stack = [] self._external_ges = 0 self._interning = None + self._namespace_prefixes = namespacePrefixesHandling # XMLReader methods @@ -126,8 +127,9 @@ def getFeature(self, name): return self._namespaces elif name == feature_string_interning: return self._interning is not None - elif name in (feature_validation, feature_external_pes, - feature_namespace_prefixes): + elif name == feature_namespace_prefixes: + return self._namespace_prefixes + elif name in (feature_validation, feature_external_pes): return 0 elif name == feature_external_ges: return self._external_ges @@ -147,6 +149,8 @@ def setFeature(self, name, state): self._interning = {} else: self._interning = None + elif name == feature_namespace_prefixes: + self._namespace_prefixes = state elif name == feature_validation: if state: raise SAXNotSupportedException( @@ -155,10 +159,6 @@ def setFeature(self, name, state): if state: raise SAXNotSupportedException( "expat does not read external parameter entities") - elif name == feature_namespace_prefixes: - if state: - raise SAXNotSupportedException( - "expat does not report namespace prefixes") else: raise SAXNotRecognizedException( "Feature '%s' not recognized" % name) @@ -347,11 +347,14 @@ def start_element_ns(self, name, attrs): pair = name.split() if len(pair) == 1: # no namespace + elem_qname = name pair = (None, name) elif len(pair) == 3: + elem_qname = "%s:%s" % (pair[2], pair[1]) pair = pair[0], pair[1] else: # default namespace + elem_qname = pair[1] pair = tuple(pair) newattrs = {} @@ -374,7 +377,7 @@ def start_element_ns(self, name, attrs): newattrs[apair] = value qnames[apair] = qname - self._cont_handler.startElementNS(pair, None, + self._cont_handler.startElementNS(pair, elem_qname, AttributesNSImpl(newattrs, qnames)) def end_element_ns(self, name): diff --git a/Misc/NEWS.d/next/Library/2024-04-26-14-21-04.gh-issue-54873.vf2bfp.rst b/Misc/NEWS.d/next/Library/2024-04-26-14-21-04.gh-issue-54873.vf2bfp.rst new file mode 100644 index 00000000000000..92c90c19b85dba --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-04-26-14-21-04.gh-issue-54873.vf2bfp.rst @@ -0,0 +1,2 @@ +Backported namespaces prefixes support for xml.sax.expatreader from PyXml +(0.8.4)