Fix xs:language pattern and XPathToken.get_results()

This commit is contained in:
Davide Brunato 2019-08-14 18:15:56 +02:00
parent bc78682fe8
commit cf59d52ca9
4 changed files with 21 additions and 14 deletions

View File

@ -1050,7 +1050,7 @@ QNAME_PATTERN = re.compile(
)
HEX_BINARY_PATTERN = re.compile(r'^[0-9a-fA-F]+$')
NOT_BASE64_BINARY_PATTERN = re.compile(r'[^0-9a-zA-z+/= \t\n]')
LANGUAGE_CODE_PATTERN = re.compile(r'^([a-zA-Z]{2}|[iI]-[a-zA-Z]+|[xX]-[a-zA-Z]{1,8})(-[a-zA-Z]{1,8})*$')
LANGUAGE_CODE_PATTERN = re.compile(r'^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$')
WRONG_ESCAPE_PATTERN = re.compile(r'%(?![a-eA-E\d]{2})')

View File

@ -275,14 +275,16 @@ class XPathToken(Token):
results = list(self.select(context))
if len(results) == 1:
res = results[0]
if isinstance(res, tuple) or is_etree_element(res) or is_document_node(res):
if isinstance(res, (bool, int, float, Decimal)):
return res
elif isinstance(res, tuple) or is_etree_element(res) or is_document_node(res):
return results
elif is_schema_node(res):
return results
elif self.symbol in ('text', 'node'):
return results
elif self.label in ('function', 'literal'):
return res
elif isinstance(res, bool): # Tests and comparisons
return res
else:
return results
else:
@ -483,13 +485,15 @@ class XPathToken(Token):
of the node. Used for schema-based dynamic evaluation of XPath expressions.
"""
try:
if obj.type.is_simple():
if obj.type.is_simple() or obj.type.has_simple_content():
# In case of schema element or attribute use a the sample value
# of the primitive type
primitive_type = self.parser.schema.get_primitive_type(obj.type)
return XSD_BUILTIN_TYPES[primitive_type.local_name].value
elif obj.type.local_name == 'anyType':
return XSD_BUILTIN_TYPES['anyType'].value
else:
return UntypedAtomic('')
except AttributeError:
raise self.wrong_type("the argument %r is not a node of an XSD schema" % obj)

View File

@ -839,13 +839,13 @@ class XPath1ParserTest(unittest.TestCase):
root = self.etree.XML(XML_DATA_TEST)
if self.parser.version == '1.0':
self.check_value("'9' + 5.0", 14)
self.check_selector("/values/a + 2", root, [5.4])
self.check_selector("/values/a + 2", root, 5.4)
self.check_value("/values/b + 2", float('nan'), context=XPathContext(root))
else:
self.check_selector("/values/a + 2", root, TypeError)
self.check_value("/values/b + 2", TypeError, context=XPathContext(root))
self.check_selector("/values/d + 3", root, [47])
self.check_selector("/values/d + 3", root, 47)
def test_numerical_mod_operator(self):
self.check_value("11 mod 3", 2)
@ -854,13 +854,13 @@ class XPath1ParserTest(unittest.TestCase):
root = self.etree.XML(XML_DATA_TEST)
if self.parser.version == '1.0':
self.check_selector("/values/a mod 2", root, [1.4])
self.check_selector("/values/a mod 2", root, 1.4)
self.check_value("/values/b mod 2", float('nan'), context=XPathContext(root))
else:
self.check_selector("/values/a mod 2", root, TypeError)
self.check_value("/values/b mod 2", TypeError, context=XPathContext(root))
self.check_selector("/values/d mod 3", root, [2])
self.check_selector("/values/d mod 3", root, 2)
def test_number_function(self):
root = self.etree.XML('<root>15</root>')
@ -1145,13 +1145,14 @@ class LxmlXPath1ParserTest(XPath1ParserTest):
else:
results = select(root, path, namespaces, self.parser.__class__, **kwargs)
variables = kwargs.get('variables', {})
if namespaces and '' in namespaces:
namespaces = {k: v for k, v in namespaces.items() if k}
if isinstance(expected, set):
if namespaces and '' not in namespaces:
self.assertEqual(set(root.xpath(path, namespaces=namespaces, **variables)), expected)
self.assertEqual(set(root.xpath(path, namespaces=namespaces, **variables)), expected)
self.assertEqual(set(results), expected)
elif not callable(expected):
if namespaces and '' not in namespaces:
self.assertEqual(root.xpath(path, namespaces=namespaces, **variables), expected)
self.assertEqual(root.xpath(path, namespaces=namespaces, **variables), expected)
self.assertEqual(results, expected)
elif isinstance(expected, type):
self.assertTrue(isinstance(results, expected))

View File

@ -657,7 +657,9 @@ class XPath2ParserTest(test_xpath1_parser.XPath1ParserTest):
self.check_value('xs:language(" en ")', "en")
self.check_value('xs:language(" en-GB ")', "en-GB")
self.check_value('xs:language("it-IT")', "it-IT")
self.wrong_value('xs:language("hello-world")')
self.check_value('xs:language("i-klingon")', 'i-klingon') # IANA-registered language
self.check_value('xs:language("x-another-language-code")', 'x-another-language-code')
self.wrong_value('xs:language("MoreThan8")')
self.check_value('xs:language(())', [])
self.check_value('xs:NMTOKEN(" :menù.09-_ ")', ":menù.09-_")