bpo-28238: Implement "{*}tag" and "{ns}*" wildcard tag selection supp… · python/cpython@4754168
@@ -1137,16 +1137,21 @@ def test_doctype_public(self):
11371137def test_xpath_tokenizer(self):
11381138# Test the XPath tokenizer.
11391139from xml.etree import ElementPath
1140-def check(p, expected):
1140+def check(p, expected, namespaces=None):
11411141self.assertEqual([op or tag
1142-for op, tag in ElementPath.xpath_tokenizer(p)],
1142+for op, tag in ElementPath.xpath_tokenizer(p, namespaces)],
11431143expected)
1144114411451145# tests from the xml specification
11461146check("*", ['*'])
1147+check("{ns}*", ['{ns}*'])
1148+check("{}*", ['{}*'])
1149+check("{*}tag", ['{*}tag'])
1150+check("{*}*", ['{*}*'])
11471151check("text()", ['text', '()'])
11481152check("@name", ['@', 'name'])
11491153check("@*", ['@', '*'])
1154+check("@{ns}attr", ['@', '{ns}attr'])
11501155check("para[1]", ['para', '[', '1', ']'])
11511156check("para[last()]", ['para', '[', 'last', '()', ']'])
11521157check("*/para", ['*', '/', 'para'])
@@ -1158,6 +1163,7 @@ def check(p, expected):
11581163check("//olist/item", ['//', 'olist', '/', 'item'])
11591164check(".", ['.'])
11601165check(".//para", ['.', '//', 'para'])
1166+check(".//{*}tag", ['.', '//', '{*}tag'])
11611167check("..", ['..'])
11621168check("../@lang", ['..', '/', '@', 'lang'])
11631169check("chapter[title]", ['chapter', '[', 'title', ']'])
@@ -1168,6 +1174,8 @@ def check(p, expected):
11681174check("{http://spam}egg", ['{http://spam}egg'])
11691175check("./spam.egg", ['.', '/', 'spam.egg'])
11701176check(".//{http://spam}egg", ['.', '//', '{http://spam}egg'])
1177+check("./xsd:type", ['.', '/', '{http://www.w3.org/2001/XMLSchema}type'],
1178+ {'xsd': 'http://www.w3.org/2001/XMLSchema'})
1171117911721180def test_processinginstruction(self):
11731181# Test ProcessingInstruction directly
@@ -2669,6 +2677,50 @@ def test_findall_different_nsmaps(self):
26692677self.assertEqual(len(root.findall(".//xx:b", namespaces=nsmap)), 2)
26702678self.assertEqual(len(root.findall(".//b", namespaces=nsmap)), 1)
267126792680+def test_findall_wildcard(self):
2681+root = ET.XML('''
2682+ <a xmlns:x="X" xmlns:y="Y">
2683+ <x:b><c/></x:b>
2684+ <b/>
2685+ <c><x:b/><b/></c><y:b/>
2686+ </a>''')
2687+root.append(ET.Comment('test'))
2688+2689+self.assertEqual(summarize_list(root.findall("{*}b")),
2690+ ['{X}b', 'b', '{Y}b'])
2691+self.assertEqual(summarize_list(root.findall("{*}c")),
2692+ ['c'])
2693+self.assertEqual(summarize_list(root.findall("{X}*")),
2694+ ['{X}b'])
2695+self.assertEqual(summarize_list(root.findall("{Y}*")),
2696+ ['{Y}b'])
2697+self.assertEqual(summarize_list(root.findall("{}*")),
2698+ ['b', 'c'])
2699+self.assertEqual(summarize_list(root.findall("{}b")), # only for consistency
2700+ ['b'])
2701+self.assertEqual(summarize_list(root.findall("{}b")),
2702+summarize_list(root.findall("b")))
2703+self.assertEqual(summarize_list(root.findall("{*}*")),
2704+ ['{X}b', 'b', 'c', '{Y}b'])
2705+# This is an unfortunate difference, but that's how find('*') works.
2706+self.assertEqual(summarize_list(root.findall("{*}*") + [root[-1]]),
2707+summarize_list(root.findall("*")))
2708+2709+self.assertEqual(summarize_list(root.findall(".//{*}b")),
2710+ ['{X}b', 'b', '{X}b', 'b', '{Y}b'])
2711+self.assertEqual(summarize_list(root.findall(".//{*}c")),
2712+ ['c', 'c'])
2713+self.assertEqual(summarize_list(root.findall(".//{X}*")),
2714+ ['{X}b', '{X}b'])
2715+self.assertEqual(summarize_list(root.findall(".//{Y}*")),
2716+ ['{Y}b'])
2717+self.assertEqual(summarize_list(root.findall(".//{}*")),
2718+ ['c', 'b', 'c', 'b'])
2719+self.assertEqual(summarize_list(root.findall(".//{}b")), # only for consistency
2720+ ['b', 'b'])
2721+self.assertEqual(summarize_list(root.findall(".//{}b")),
2722+summarize_list(root.findall(".//b")))
2723+26722724def test_bad_find(self):
26732725e = ET.XML(SAMPLE_XML)
26742726with self.assertRaisesRegex(SyntaxError, 'cannot use absolute path'):