Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
243a74c
gh-140123: Make ElementTree.find use registered global namespaces
sangampaudel530 Oct 20, 2025
0ddb4cb
GH-140123: ElementTree.find uses registered namespaces when omitted
sangampaudel530 Oct 20, 2025
95cddc9
xml.etree: Fix namespace prefix resolution in ElementPath xpath_token…
sangampaudel530 Oct 20, 2025
e3997b0
Fix linter issues: Remove duplicate ET import and add missing newline
sangampaudel530 Oct 20, 2025
c5d1512
Keep full NEWS entry for #140123, remove duplicate draft
sangampaudel530 Oct 20, 2025
b2f5757
Rename NEWS entry to include section for blurb: #140123
sangampaudel530 Oct 20, 2025
9eda02e
fix blurb format error
sangampaudel530 Oct 20, 2025
af2dfbf
Deleted News file causing failing tests
sangampaudel530 Oct 21, 2025
8ae041c
Fix: avoid mutable default arguments in ElementTree
sangampaudel530 Oct 21, 2025
8d49958
gh-140123: Make ElementTree.find use registered global namespaces
sangampaudel530 Oct 20, 2025
49d517d
GH-140123: ElementTree.find uses registered namespaces when omitted
sangampaudel530 Oct 20, 2025
145d47f
xml.etree: Fix namespace prefix resolution in ElementPath xpath_token…
sangampaudel530 Oct 20, 2025
0a86da9
Fix linter issues: Remove duplicate ET import and add missing newline
sangampaudel530 Oct 20, 2025
28c55c8
Keep full NEWS entry for #140123, remove duplicate draft
sangampaudel530 Oct 20, 2025
1a9208e
Rename NEWS entry to include section for blurb: #140123
sangampaudel530 Oct 20, 2025
ef4fd3f
fix blurb format error
sangampaudel530 Oct 20, 2025
33d8aac
Deleted News file causing failing tests
sangampaudel530 Oct 21, 2025
8c6a6e4
📜🤖 Added by blurb_it.
blurb-it[bot] Oct 21, 2025
b76e833
xml.etree: Fix XMLParser parser attribute handling
sangampaudel530 Oct 21, 2025
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
29 changes: 28 additions & 1 deletion Lib/test/test_xml_etree.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
from test.support.import_helper import import_fresh_module
from test.support.os_helper import TESTFN


# pyET is the pure-Python implementation.
#
# ET is pyET in test_xml_etree and is the C accelerated version in
Expand Down Expand Up @@ -4668,6 +4667,34 @@ def cleanup():
old_factories = ET._set_factories(ET.Comment, ET.PI)
unittest.addModuleCleanup(ET._set_factories, *old_factories)

class TestElementTreeGlobalNamespace(unittest.TestCase):
def test_find_uses_registered_namespace(self):
xml_data = """<root>
<h:title xmlns:h="http://www.w3.org/TR/html4/">
<h:tr><h:td>Apple</h:td></h:tr>
</h:title>
</root>"""
ET.register_namespace("h", "http://www.w3.org/TR/html4/")
tree = ET.ElementTree(ET.fromstring(xml_data))

# should work without passing namespaces explicitly
elem = tree.find(".//h:title")
self.assertIsNotNone(elem)
self.assertEqual(elem.tag, "{http://www.w3.org/TR/html4/}title")

def test_findall_and_findtext_with_global_ns(self):
xml_data = """<root xmlns:h="http://www.w3.org/TR/html4/">
<h:item>Apple</h:item>
<h:item>Banana</h:item>
</root>"""
ET.register_namespace("h", "http://www.w3.org/TR/html4/")
root = ET.fromstring(xml_data)

items = root.findall(".//h:item")
self.assertEqual(len(items), 2)

first_text = root.findtext(".//h:item")
self.assertEqual(first_text, "Apple")

if __name__ == '__main__':
unittest.main()
13 changes: 9 additions & 4 deletions Lib/xml/etree/ElementPath.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#
# [email protected]
# http://www.pythonware.com

from . import ElementTree
#
# --------------------------------------------------------------------
# The ElementTree toolkit is
Expand Down Expand Up @@ -79,11 +81,14 @@ def xpath_tokenizer(pattern, namespaces=None):
if tag and tag[0] != "{":
if ":" in tag:
prefix, uri = tag.split(":", 1)
try:
if not namespaces:
raise KeyError
if namespaces and prefix in namespaces:
# Use the passed-in namespace map first
yield ttype, "{%s}%s" % (namespaces[prefix], uri)
except KeyError:
elif prefix in ElementTree._namespace_map:
# Then check the global registry
yield ttype, "{%s}%s" % (ElementTree._namespace_map[prefix], uri)
else:
# No namespace found, raise error
raise SyntaxError("prefix %r not found in prefix map" % prefix) from None
elif default_namespace and not parsing_attribute:
yield ttype, "{%s}%s" % (default_namespace, tag)
Expand Down
15 changes: 13 additions & 2 deletions Lib/xml/etree/ElementTree.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
import weakref

from . import ElementPath
import xml.etree.ElementTree as _ET


class ParseError(SyntaxError):
Expand Down Expand Up @@ -167,7 +168,9 @@ class Element:

"""

def __init__(self, tag, attrib={}, **extra):
def __init__(self, tag, attrib=None, **extra):
if attrib is None:
attrib = {}
if not isinstance(attrib, dict):
raise TypeError("attrib must be dict, not %s" % (
attrib.__class__.__name__,))
Expand Down Expand Up @@ -282,6 +285,8 @@ def find(self, path, namespaces=None):
Return the first matching element, or None if no element was found.

"""
if namespaces is None:
namespaces = {v: k for k, v in _ET._namespace_map.items() if v}
return ElementPath.find(self, path, namespaces)

def findtext(self, path, default=None, namespaces=None):
Expand All @@ -296,6 +301,8 @@ def findtext(self, path, default=None, namespaces=None):
content, the empty string is returned.

"""
if namespaces is None:
namespaces = {v: k for k, v in _ET._namespace_map.items() if v}
return ElementPath.findtext(self, path, default, namespaces)

def findall(self, path, namespaces=None):
Expand All @@ -307,6 +314,8 @@ def findall(self, path, namespaces=None):
Returns list containing all matching elements in document order.

"""
if namespaces is None:
namespaces = {v: k for k, v in _ET._namespace_map.items() if v}
return ElementPath.findall(self, path, namespaces)

def iterfind(self, path, namespaces=None):
Expand All @@ -318,6 +327,8 @@ def iterfind(self, path, namespaces=None):
Return an iterable yielding all matching elements in document order.

"""
if namespaces is None:
namespaces = {v: k for k, v in _ET._namespace_map.items() if v}
return ElementPath.iterfind(self, path, namespaces)

def clear(self):
Expand Down Expand Up @@ -1540,7 +1551,7 @@ def __init__(self, *, target=None, encoding=None):
parser = expat.ParserCreate(encoding, "}")
if target is None:
target = TreeBuilder()
# underscored names are provided for compatibility only
# both names are provided for compatibility
self.parser = self._parser = parser
self.target = self._target = target
self._error = expat.error
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ElementTree.find(), ElementTree.findall(), and ElementTree.findtext() now
use registered namespaces consistently with ElementPath.
Loading