diff options
author | Ammar Askar <ammar@ammaraskar.com> | 2020-11-09 07:02:39 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-09 07:02:39 (GMT) |
commit | 97e8b1eaeaf3aa325c84ff2e13417c30414d0269 (patch) | |
tree | d1979f9ac520d18afa0e089568dfb92794a64e44 /Lib/xml | |
parent | 4eb41d055e8307b8206f680287e492a6db068acd (diff) | |
download | cpython-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.py | 31 |
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 == "-": |