bpo-40624: Add support for the XPath != operator in xml.etree (GH-22147)

This commit is contained in:
Ammar Askar 2020-11-09 02:02:39 -05:00 committed by GitHub
parent 4eb41d055e
commit 97e8b1eaea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 78 additions and 7 deletions

View file

@ -65,8 +65,9 @@ xpath_tokenizer_re = re.compile(
r"//?|"
r"\.\.|"
r"\(\)|"
r"!=|"
r"[/.*:\[\]\(\)@=])|"
r"((?:\{[^}]+\})?[^/\[\]\(\)@=\s]+)|"
r"((?:\{[^}]+\})?[^/\[\]\(\)@!=\s]+)|"
r"\s+"
)
@ -253,15 +254,19 @@ def prepare_predicate(next, token):
if elem.get(key) is not None:
yield elem
return select
if signature == "@-='":
# [@attribute='value']
if signature == "@-='" or signature == "@-!='":
# [@attribute='value'] or [@attribute!='value']
key = predicate[1]
value = predicate[-1]
def select(context, result):
for elem in result:
if elem.get(key) == value:
yield elem
return select
def select_negated(context, result):
for elem in result:
if (attr_value := elem.get(key)) is not None and attr_value != value:
yield elem
return select_negated if '!=' in signature else select
if signature == "-" and not re.match(r"\-?\d+$", predicate[0]):
# [tag]
tag = predicate[0]
@ -270,8 +275,10 @@ def prepare_predicate(next, token):
if elem.find(tag) is not None:
yield elem
return select
if signature == ".='" or (signature == "-='" and not re.match(r"\-?\d+$", predicate[0])):
# [.='value'] or [tag='value']
if signature == ".='" or signature == ".!='" or (
(signature == "-='" or signature == "-!='")
and not re.match(r"\-?\d+$", predicate[0])):
# [.='value'] or [tag='value'] or [.!='value'] or [tag!='value']
tag = predicate[0]
value = predicate[-1]
if tag:
@ -281,12 +288,22 @@ def prepare_predicate(next, token):
if "".join(e.itertext()) == value:
yield elem
break
def select_negated(context, result):
for elem in result:
for e in elem.iterfind(tag):
if "".join(e.itertext()) != value:
yield elem
break
else:
def select(context, result):
for elem in result:
if "".join(elem.itertext()) == value:
yield elem
return select
def select_negated(context, result):
for elem in result:
if "".join(elem.itertext()) != value:
yield elem
return select_negated if '!=' in signature else select
if signature == "-" or signature == "-()" or signature == "-()-":
# [index] or [last()] or [last()-index]
if signature == "-":