summaryrefslogtreecommitdiffstats
path: root/Lib/xml
diff options
context:
space:
mode:
authorAmmar Askar <ammar@ammaraskar.com>2020-11-09 07:02:39 (GMT)
committerGitHub <noreply@github.com>2020-11-09 07:02:39 (GMT)
commit97e8b1eaeaf3aa325c84ff2e13417c30414d0269 (patch)
treed1979f9ac520d18afa0e089568dfb92794a64e44 /Lib/xml
parent4eb41d055e8307b8206f680287e492a6db068acd (diff)
downloadcpython-97e8b1eaeaf3aa325c84ff2e13417c30414d0269.zip
cpython-97e8b1eaeaf3aa325c84ff2e13417c30414d0269.tar.gz
cpython-97e8b1eaeaf3aa325c84ff2e13417c30414d0269.tar.bz2
bpo-40624: Add support for the XPath != operator in xml.etree (GH-22147)
Diffstat (limited to 'Lib/xml')
-rw-r--r--Lib/xml/etree/ElementPath.py31
1 files changed, 24 insertions, 7 deletions
diff --git a/Lib/xml/etree/ElementPath.py b/Lib/xml/etree/ElementPath.py
index d318e65..1cbd839 100644
--- a/Lib/xml/etree/ElementPath.py
+++ b/Lib/xml/etree/ElementPath.py
@@ -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 == "-":