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

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 @@
     r"//?|"
     r"\.\.|"
     r"\(\)|"
+    r"!=|"
     r"[/.*:\[\]\(\)@=])|"
-    r"((?:\{[^}]+\})?[^/\[\]\(\)@=\s]+)|"
+    r"((?:\{[^}]+\})?[^/\[\]\(\)@!=\s]+)|"
     r"\s+"
     )
 
@@ -253,15 +254,19 @@ def select(context, result):
                 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 select(context, result):
                 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 select(context, result):
                         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 == "-":