Skip to content

Commit 243a74c

Browse files
gh-140123: Make ElementTree.find use registered global namespaces
ElementTree.find, findall, findtext, and iterfind now use the global _namespace_map as fallback when no namespaces argument is provided. Fixes inconsistencies between ElementTree and ElementPath when using ET.register_namespace.
1 parent b2f9fb9 commit 243a74c

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed

Lib/test/test_xml_etree.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import unittest.mock as mock
2222
import warnings
2323
import weakref
24+
import xml.etree.ElementTree as ET
2425

2526
from contextlib import nullcontext
2627
from functools import partial
@@ -32,7 +33,6 @@
3233
from test.support.import_helper import import_fresh_module
3334
from test.support.os_helper import TESTFN
3435

35-
3636
# pyET is the pure-Python implementation.
3737
#
3838
# ET is pyET in test_xml_etree and is the C accelerated version in
@@ -4668,6 +4668,34 @@ def cleanup():
46684668
old_factories = ET._set_factories(ET.Comment, ET.PI)
46694669
unittest.addModuleCleanup(ET._set_factories, *old_factories)
46704670

4671+
class TestElementTreeGlobalNamespace(unittest.TestCase):
4672+
def test_find_uses_registered_namespace(self):
4673+
xml_data = """<root>
4674+
<h:title xmlns:h="http://www.w3.org/TR/html4/">
4675+
<h:tr><h:td>Apple</h:td></h:tr>
4676+
</h:title>
4677+
</root>"""
4678+
ET.register_namespace("h", "http://www.w3.org/TR/html4/")
4679+
tree = ET.ElementTree(ET.fromstring(xml_data))
4680+
4681+
# should work without passing namespaces explicitly
4682+
elem = tree.find(".//h:title")
4683+
self.assertIsNotNone(elem)
4684+
self.assertEqual(elem.tag, "{http://www.w3.org/TR/html4/}title")
4685+
4686+
def test_findall_and_findtext_with_global_ns(self):
4687+
xml_data = """<root xmlns:h="http://www.w3.org/TR/html4/">
4688+
<h:item>Apple</h:item>
4689+
<h:item>Banana</h:item>
4690+
</root>"""
4691+
ET.register_namespace("h", "http://www.w3.org/TR/html4/")
4692+
root = ET.fromstring(xml_data)
4693+
4694+
items = root.findall(".//h:item")
4695+
self.assertEqual(len(items), 2)
4696+
4697+
first_text = root.findtext(".//h:item")
4698+
self.assertEqual(first_text, "Apple")
46714699

46724700
if __name__ == '__main__':
46734701
unittest.main()

Lib/xml/etree/ElementTree.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
import weakref
103103

104104
from . import ElementPath
105+
import xml.etree.ElementTree as _ET
105106

106107

107108
class ParseError(SyntaxError):
@@ -282,6 +283,8 @@ def find(self, path, namespaces=None):
282283
Return the first matching element, or None if no element was found.
283284
284285
"""
286+
if namespaces is None:
287+
namespaces = {v: k for k, v in _ET._namespace_map.items() if v}
285288
return ElementPath.find(self, path, namespaces)
286289

287290
def findtext(self, path, default=None, namespaces=None):
@@ -296,6 +299,8 @@ def findtext(self, path, default=None, namespaces=None):
296299
content, the empty string is returned.
297300
298301
"""
302+
if namespaces is None:
303+
namespaces = {v: k for k, v in _ET._namespace_map.items() if v}
299304
return ElementPath.findtext(self, path, default, namespaces)
300305

301306
def findall(self, path, namespaces=None):
@@ -307,6 +312,8 @@ def findall(self, path, namespaces=None):
307312
Returns list containing all matching elements in document order.
308313
309314
"""
315+
if namespaces is None:
316+
namespaces = {v: k for k, v in _ET._namespace_map.items() if v}
310317
return ElementPath.findall(self, path, namespaces)
311318

312319
def iterfind(self, path, namespaces=None):
@@ -318,6 +325,8 @@ def iterfind(self, path, namespaces=None):
318325
Return an iterable yielding all matching elements in document order.
319326
320327
"""
328+
if namespaces is None:
329+
namespaces = {v: k for k, v in _ET._namespace_map.items() if v}
321330
return ElementPath.iterfind(self, path, namespaces)
322331

323332
def clear(self):

0 commit comments

Comments
 (0)