Fix cast() to accept tuples for XPath constructors

This commit is contained in:
Davide Brunato 2019-10-09 17:19:46 +02:00
parent d11524f50b
commit 583d1eb14b
1 changed files with 56 additions and 2 deletions

View File

@ -38,16 +38,23 @@ constructor = XPath2Parser.constructor
# Constructors for string-based XSD types # Constructors for string-based XSD types
@constructor('normalizedString') @constructor('normalizedString')
def cast(value): def cast(value):
if isinstance(value, tuple):
value = value[-1]
return str(value).replace('\t', ' ').replace('\n', ' ') return str(value).replace('\t', ' ').replace('\n', ' ')
@constructor('token') @constructor('token')
def cast(value): def cast(value):
if isinstance(value, tuple):
value = value[-1]
return collapse_white_spaces(value) return collapse_white_spaces(value)
@constructor('language') @constructor('language')
def cast(value): def cast(value):
if isinstance(value, tuple):
value = value[-1]
match = LANGUAGE_CODE_PATTERN.match(collapse_white_spaces(value)) match = LANGUAGE_CODE_PATTERN.match(collapse_white_spaces(value))
if match is None: if match is None:
raise xpath_error('FOCA0002', "%r is not a language code" % value) raise xpath_error('FOCA0002', "%r is not a language code" % value)
@ -56,6 +63,9 @@ def cast(value):
@constructor('NMTOKEN') @constructor('NMTOKEN')
def cast(value): def cast(value):
if isinstance(value, tuple):
value = value[-1]
match = NMTOKEN_PATTERN.match(collapse_white_spaces(value)) match = NMTOKEN_PATTERN.match(collapse_white_spaces(value))
if match is None: if match is None:
raise xpath_error('FOCA0002', "%r is not an xs:NMTOKEN value" % value) raise xpath_error('FOCA0002', "%r is not an xs:NMTOKEN value" % value)
@ -64,6 +74,9 @@ def cast(value):
@constructor('Name') @constructor('Name')
def cast(value): def cast(value):
if isinstance(value, tuple):
value = value[-1]
match = NAME_PATTERN.match(collapse_white_spaces(value)) match = NAME_PATTERN.match(collapse_white_spaces(value))
if match is None: if match is None:
raise xpath_error('FOCA0002', "%r is not an xs:Name value" % value) raise xpath_error('FOCA0002', "%r is not an xs:Name value" % value)
@ -75,6 +88,9 @@ def cast(value):
@constructor('IDREF') @constructor('IDREF')
@constructor('ENTITY') @constructor('ENTITY')
def cast(value): def cast(value):
if isinstance(value, tuple):
value = value[-1]
match = NCNAME_PATTERN.match(collapse_white_spaces(value)) match = NCNAME_PATTERN.match(collapse_white_spaces(value))
if match is None: if match is None:
raise xpath_error('FOCA0002', "invalid value %r for constructor" % value) raise xpath_error('FOCA0002', "invalid value %r for constructor" % value)
@ -83,6 +99,9 @@ def cast(value):
@constructor('anyURI') @constructor('anyURI')
def cast(value): def cast(value):
if isinstance(value, tuple):
value = value[-1]
uri = collapse_white_spaces(value) uri = collapse_white_spaces(value)
try: try:
urlparse(uri) urlparse(uri)
@ -99,6 +118,8 @@ def cast(value):
# Constructors for numeric XSD types # Constructors for numeric XSD types
@constructor('decimal') @constructor('decimal')
def cast(value): def cast(value):
if isinstance(value, tuple):
value = value[-1]
try: try:
return decimal.Decimal(value) return decimal.Decimal(value)
except (ValueError, decimal.DecimalException) as err: except (ValueError, decimal.DecimalException) as err:
@ -108,6 +129,8 @@ def cast(value):
@constructor('double') @constructor('double')
@constructor('float') @constructor('float')
def cast(value): def cast(value):
if isinstance(value, tuple):
value = value[-1]
try: try:
return float(value) return float(value)
except ValueError as err: except ValueError as err:
@ -125,6 +148,9 @@ def cast_to_integer(value, lower_bound=None, higher_bound=None):
:raise: an `ElementPathValueError` if the value is not decodable to an integer or if \ :raise: an `ElementPathValueError` if the value is not decodable to an integer or if \
the value is out of bounds. the value is out of bounds.
""" """
if isinstance(value, tuple):
value = value[-1]
if isinstance(value, string_base_type): if isinstance(value, string_base_type):
try: try:
result = int(float(value)) result = int(float(value))
@ -212,15 +238,17 @@ def cast(value):
# Constructors for datetime XSD types # Constructors for datetime XSD types
@constructor('date') @constructor('date')
def cast(value, tz=None): def cast(value, tz=None):
if isinstance(value, tuple):
value = value[-1]
if isinstance(value, Date10): if isinstance(value, Date10):
return value return value
elif isinstance(value, UntypedAtomic):
return Date10.fromstring(str(value), tzinfo=tz)
return Date10.fromstring(value, tzinfo=tz) return Date10.fromstring(value, tzinfo=tz)
@constructor('gDay') @constructor('gDay')
def cast(value, tz=None): def cast(value, tz=None):
if isinstance(value, tuple):
value = value[-1]
if isinstance(value, XPathGregorianDay): if isinstance(value, XPathGregorianDay):
return value return value
return XPathGregorianDay.fromstring(value, tzinfo=tz) return XPathGregorianDay.fromstring(value, tzinfo=tz)
@ -228,6 +256,8 @@ def cast(value, tz=None):
@constructor('gMonth') @constructor('gMonth')
def cast(value, tz=None): def cast(value, tz=None):
if isinstance(value, tuple):
value = value[-1]
if isinstance(value, XPathGregorianMonth): if isinstance(value, XPathGregorianMonth):
return value return value
return XPathGregorianMonth.fromstring(value, tzinfo=tz) return XPathGregorianMonth.fromstring(value, tzinfo=tz)
@ -235,6 +265,8 @@ def cast(value, tz=None):
@constructor('gMonthDay') @constructor('gMonthDay')
def cast(value, tz=None): def cast(value, tz=None):
if isinstance(value, tuple):
value = value[-1]
if isinstance(value, XPathGregorianMonthDay): if isinstance(value, XPathGregorianMonthDay):
return value return value
return XPathGregorianMonthDay.fromstring(value, tzinfo=tz) return XPathGregorianMonthDay.fromstring(value, tzinfo=tz)
@ -242,6 +274,8 @@ def cast(value, tz=None):
@constructor('gYear') @constructor('gYear')
def cast(value, tz=None): def cast(value, tz=None):
if isinstance(value, tuple):
value = value[-1]
if isinstance(value, XPathGregorianYear): if isinstance(value, XPathGregorianYear):
return value return value
return XPathGregorianYear.fromstring(value, tzinfo=tz) return XPathGregorianYear.fromstring(value, tzinfo=tz)
@ -249,6 +283,8 @@ def cast(value, tz=None):
@constructor('gYearMonth') @constructor('gYearMonth')
def cast(value, tz=None): def cast(value, tz=None):
if isinstance(value, tuple):
value = value[-1]
if isinstance(value, XPathGregorianYearMonth): if isinstance(value, XPathGregorianYearMonth):
return value return value
return XPathGregorianYearMonth.fromstring(value, tzinfo=tz) return XPathGregorianYearMonth.fromstring(value, tzinfo=tz)
@ -256,6 +292,8 @@ def cast(value, tz=None):
@constructor('time') @constructor('time')
def cast(value, tz=None): def cast(value, tz=None):
if isinstance(value, tuple):
value = value[-1]
if isinstance(value, Time): if isinstance(value, Time):
return value return value
return Time.fromstring(value, tzinfo=tz) return Time.fromstring(value, tzinfo=tz)
@ -284,16 +322,28 @@ def evaluate(self, context=None):
# Constructors for time durations XSD types # Constructors for time durations XSD types
@constructor('duration') @constructor('duration')
def cast(value): def cast(value):
if isinstance(value, tuple):
value = value[-1]
if isinstance(value, Duration):
return value
return Duration.fromstring(value) return Duration.fromstring(value)
@constructor('yearMonthDuration') @constructor('yearMonthDuration')
def cast(value): def cast(value):
if isinstance(value, tuple):
value = value[-1]
if isinstance(value, YearMonthDuration):
return value
return YearMonthDuration.fromstring(value) return YearMonthDuration.fromstring(value)
@constructor('dayTimeDuration') @constructor('dayTimeDuration')
def cast(value): def cast(value):
if isinstance(value, tuple):
value = value[-1]
if isinstance(value, DayTimeDuration):
return value
return DayTimeDuration.fromstring(value) return DayTimeDuration.fromstring(value)
@ -301,6 +351,8 @@ def cast(value):
# Constructors for binary XSD types # Constructors for binary XSD types
@constructor('base64Binary') @constructor('base64Binary')
def cast(value, from_literal=False): def cast(value, from_literal=False):
if isinstance(value, tuple):
value = value[-1]
if isinstance(value, UntypedAtomic): if isinstance(value, UntypedAtomic):
return codecs.encode(unicode_type(value), 'base64') return codecs.encode(unicode_type(value), 'base64')
elif not isinstance(value, (bytes, unicode_type)): elif not isinstance(value, (bytes, unicode_type)):
@ -318,6 +370,8 @@ def cast(value, from_literal=False):
@constructor('hexBinary') @constructor('hexBinary')
def cast(value, from_literal=False): def cast(value, from_literal=False):
if isinstance(value, tuple):
value = value[-1]
if isinstance(value, UntypedAtomic): if isinstance(value, UntypedAtomic):
return codecs.encode(unicode_type(value), 'hex') return codecs.encode(unicode_type(value), 'hex')
elif not isinstance(value, (bytes, unicode_type)): elif not isinstance(value, (bytes, unicode_type)):