bpo-30485: support a default prefix mapping in ElementPath by passing None as prefix (#1823)

This commit is contained in:
Stefan Behnel 2019-04-14 10:09:09 +02:00 committed by GitHub
parent ffca16e25a
commit e9927e1820
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 12 deletions

View file

@ -71,16 +71,22 @@ xpath_tokenizer_re = re.compile(
)
def xpath_tokenizer(pattern, namespaces=None):
default_namespace = namespaces.get(None) if namespaces else None
for token in xpath_tokenizer_re.findall(pattern):
tag = token[1]
if tag and tag[0] != "{" and ":" in tag:
try:
if tag and tag[0] != "{":
if ":" in tag:
prefix, uri = tag.split(":", 1)
if not namespaces:
raise KeyError
yield token[0], "{%s}%s" % (namespaces[prefix], uri)
except KeyError:
raise SyntaxError("prefix %r not found in prefix map" % prefix) from None
try:
if not namespaces:
raise KeyError
yield token[0], "{%s}%s" % (namespaces[prefix], uri)
except KeyError:
raise SyntaxError("prefix %r not found in prefix map" % prefix) from None
elif default_namespace:
yield token[0], "{%s}%s" % (default_namespace, tag)
else:
yield token
else:
yield token
@ -264,10 +270,19 @@ class _SelectorContext:
def iterfind(elem, path, namespaces=None):
# compile selector pattern
cache_key = (path, None if namespaces is None
else tuple(sorted(namespaces.items())))
if path[-1:] == "/":
path = path + "*" # implicit all (FIXME: keep this?)
cache_key = (path,)
if namespaces:
if '' in namespaces:
raise ValueError("empty namespace prefix must be passed as None, not the empty string")
if None in namespaces:
cache_key += (namespaces[None],) + tuple(sorted(
item for item in namespaces.items() if item[0] is not None))
else:
cache_key += tuple(sorted(namespaces.items()))
try:
selector = _cache[cache_key]
except KeyError: