RDFClosure.DatatypeHandling

Package RDFClosure :: Module DatatypeHandling |
[hide private]
[frames] | no frames]

# Source Code for Module RDFClosure.DatatypeHandling

      1  #!/d/Bin/Python/python.exe
      2  # -*- coding: utf-8 -*-
      3  #
      4  """
      5  Most of the XSD datatypes are handled directly by RDFLib. However, in some cases, that is not good enough. There are two
      6  major reasons for this:
      7
      8   1. Some datatypes are missing from RDFLib and required by OWL 2 RL and/or RDFS
      9   2. In other cases, though the datatype is present, RDFLib is fairly lax in checking the lexical value of those datatypes. Typical case is boolean.
     10
     11  Some of these deficiencies are handled by this module. All the functions convert the lexical value into a
     12  python datatype (or return the original string if this is not possible) which will be used, eg,
     13  for comparisons (equalities). If the lexical value constraints are not met, exceptions are raised.
     14
     15  @requires: U{RDFLib<https://github.com/RDFLib/rdflib>}, 4.0.0 and higher
     16  @license: This software is available for use under the U{W3C Software License<http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231>}
     17  @organization: U{World Wide Web Consortium<http://www.w3.org>}
     18  @author: U{Ivan Herman<a href="http://www.w3.org/People/Ivan/">}
     19  """
     20
     21  __author__  = 'Ivan Herman'
     22  __contact__ = 'Ivan Herman, ivan@w3.org'
     23  __license__ = u'W3C® SOFTWARE NOTICE AND LICENSE, http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231'
     24
     25  # noinspection PyPep8Naming
     26  from RDFClosure.RDFS import RDFNS as ns_rdf
     27
     28  from rdflib.term import XSDToPython, Literal, _toPythonMapping
     29  # noinspection PyPep8Naming
     30  from rdflib.namespace import XSD as ns_xsd
     31
     32  import datetime, time, re
     33  from decimal import Decimal
     34
     35  # noinspection PyMissingConstructor,PyPep8Naming
     36 -class _namelessTZ(datetime.tzinfo):
     37          """(Nameless) timezone object. The python datetime object requires timezones as
     38          a specific object added to the conversion, rather than the explicit hour and minute
     39          difference used by XSD. This class is used to wrap around the hour/minute values.
     40          """
     41 -        def __init__(self, hours, minutes):
     42                  """
     43                  @param hours: hour offset
     44                  @param minutes: minute offset
     45                  """
     46                  self.__offset = datetime.timedelta(hours=hours, minutes=minutes)
     47                  self.__name = "nameless"
     48
     49 -        def utcoffset(self, dt):
     50                  return self.__offset
     51
     52 -        def tzname(self, dt):
     53                  return self.__name
     54
     55 -        def dst(self, dt):
     56                  return datetime.timedelta(0)
     57
     58  # noinspection PyPep8Naming
     59 -def _returnTimeZone(incoming_v):
     60          """Almost all time/date related methods require the extraction of an optional time zone information.
     61          @param incoming_v: the time/date string
     62          @return (v,timezone) tuple; 'v' is the input string with the timezone info cut off, 'timezone' is a L{_namelessTZ} instance or None
     63          """
     64          if incoming_v[-1] == 'Z':
     65                  v     = incoming_v[:-1]
     66                  tzone = _namelessTZ(0,0)
     67          else :
     68                  pattern = ".*(\+|-)([0-9][0-9]):([0-9][0-9])"
     69                  match   = re.match(pattern,incoming_v)
     70                  if match is None:
     71                          v     = incoming_v
     72                          tzone = None
     73                  else :
     74                          hours   = int(match.groups()[1])
     75                          if match.groups()[0] == '-':
     76                                  hours = -hours - 1
     77                          minutes = int(match.groups()[2])
     78                          v     = incoming_v[:-6]
     79                          tzone = _namelessTZ(hours,minutes)
     80          return v, tzone
     81
     82
     83  #################################### Booleans ##################################################
     84  # noinspection PyPep8Naming
     85 -def _strToBool(v) :
     86          """The built-in conversion to boolean is way too lax. The xsd specification requires that only true, false, 1 or 0 should be used...
     87          @param v: the literal string defined as boolean
     88          @return corresponding boolean value
     89          @raise ValueError: invalid boolean values
     90          """
     91          if v.lower() == "true" or v.lower() == "1":
     92                  return True
     93          elif v.lower() == "false" or v.lower() == "0":
     94                  return False
     95          else :
     96                  raise ValueError("Invalid boolean literal value %s" % v)
     97
     98
     99  #################################### Decimals ##################################################
    100  # noinspection PyPep8Naming
    101 -def _strToDecimal(v) :
    102          """The built in datatype handling for RDFLib maps a decimal number to float, but the python version 2.4 and upwards also
    103          has a Decimal number. Better make use of that to use very high numbers.
    104          However, there is also a big difference between Python's decimal and XSD's decimal, because the latter does not allow
    105          for an exponential normal form (why???). This must be filtered out.
    106          @param v: the literal string defined as decimal
    107          @return Decimal
    108          @raise ValueError: invalid decimal value
    109          """
    110          # check whether the lexical form of 'v' is o.k.
    111          if v.find('E') != -1 or v.find('e') != -1 :
    112                  # this is an invalid lexical form, though would be accepted by Python
    113                  raise ValueError("Invalid decimal literal value %s" % v)
    114          else :
    115                  return Decimal(v)
    116
    117  #################################### ANY URIS ##################################################
    118  #: set of characters allowed in a hexadecimal number
    119  _hexc = ['A','B','C','D','E','F','a','b','c','d','e','f']
    120  #: set of numerals
    121  _numb = ['1','2','3','4','5','6','7','8','9','0']
    122  # noinspection PyPep8Naming
    123 -def _strToAnyURI(v) :
    124          """Rudimentary test for the AnyURI value. If it is a relative URI, then some tests are done to filter out
    125          mistakes. I am not sure this is the full implementation of the RFC, though, may have to be checked at some point
    126          later.
    127          @param v: the literal string defined as a URI
    128          @return the incoming value
    129          @raise ValueError: invalid URI value
    130          """
    131          import urlparse
    132          if len(v) == 0 : return v
    133          if urlparse.urlsplit(v)[0] != "":
    134                  # this means that there is a proper scheme, the URI should be kosher
    135                  return v
    136          else :
    137                  # this is meant to be a relative URI.
    138                  # If I am correct, that cannot begin with one or more "?" or ":" characters
    139                  # all others are o.k.
    140                  # if it begins with a % then it should be followed by two hexa characters,
    141                  # otherwise it is also a bug
    142                  if v[0] == '%':
    143                          if len(v) >= 3 and (v[1] in _hexc or v[1] in _numb) and (v[2] in _hexc or v[2] in _numb) :
    144                                  return v
    145                          else :
    146                                  raise ValueError("Invalid IRI %s" % v)
    147                  elif v[0] == '?' or v[0] == ':':
    148                          raise ValueError("Invalid IRI %s" % v)
    149                  else :
    150                          return v
    151
    152  #################################### Base64Binary ##################################################
    153  # noinspection PyPep8Naming
    154 -def _strToBase64Binary(v) :
    155          """Rudimentary test for the base64Binary value. The problem is that the built-in b64 module functions ignore the
    156          fact that only a certain family of characters are allowed to appear in the lexical value, so this is checked first.
    157          @param v: the literal string defined as a base64encoded string
    158          @return the decoded (binary) content
    159          @raise ValueError: invalid base 64 binary value
    160          """
    161          import base64
    162          if v.replace('=', 'x').replace('+', 'y').replace('/', 'z').isalnum() :
    163                  try :
    164                          return base64.standard_b64decode(v)
    165                  except :
    166                          raise ValueError("Invalid Base64Binary %s" % v)
    167          else :
    168                  raise ValueError("Invalid Base64Binary %s" % v)
    169
    170  #################################### Numerical types ##################################################
    171  #: limits for unsigned bytes
    172  _limits_unsignedByte            = [-1, 256]
    173
    174  #: limits for bytes
    175  _limits_byte                            = [-129, 128]
    176
    177  #: limits for unsigned int
    178  _limits_unsignedInt                     = [-1, 4294967296]
    179
    180  #: limits for int
    181  _limits_int                                     = [-2147483649, 2147483648]
    182
    183  #: limits for unsigned short
    184  _limits_unsignedShort           = [-1, 65536]
    185
    186  #: limits for short
    187  _limits_short                           = [-32769, 32768]
    188
    189  #: limits for unsigned long
    190  _limits_unsignedLong            = [-1, 18446744073709551616]
    191
    192  #: limits for long
    193  _limits_long                            = [-9223372036854775809, 9223372036854775808]
    194
    195  #: limits for positive integer
    196  _limits_positiveInteger         = [0, None]
    197
    198  #: limits for non positive integer
    199  _limits_nonPositiveInteger      = [None, 1]
    200
    201  #: limits for non negative integer
    202  _limits_nonNegativeInteger      = [-1, None]
    203
    204  #: limits for negative integer
    205  _limits_negativeInteger         = [None, 0]
    206
    207  # noinspection PyPep8Naming,PyBroadException
    208 -def _strToBoundNumeral(v, interval, conversion) :
    209          """Test (and convert) a generic numerical type, with a check against a lower and upper limit.
    210          @param v: the literal string to be converted
    211          @param interval: lower and upper bounds (non inclusive). If the value is None, no comparison should be done
    212          @param conversion: conversion function, ie, int, long, etc
    213          @raise ValueError: invalid value
    214          """
    215          try:
    216                  i = conversion(v)
    217                  if (interval[0] is None or interval[0] < i) and (interval[1] is None or i < interval[1]) :
    218                          return i
    219          except:
    220                  pass
    221          raise ValueError("Invalid numerical value %s" % v)
    222
    223  #################################### Double and float ##################################################
    224  # noinspection PyPep8Naming
    225 -def _strToDouble(v):
    226          """Test and convert a double value into a Decimal or float. Raises an exception if the number is outside the permitted
    227          range, ie, 1.0E+310 and 1.0E-330. To be on the safe side (python does not have double!) Decimals are used
    228          if possible. Upper and lower values, as required by xsd, are checked (and these fixed values are the reasons
    229          why Decimal is used!)
    230
    231          @param v: the literal string defined as a double
    232          @return Decimal
    233          @raise ValueError: invalid value
    234          """
    235          try :
    236                  value = Decimal(v)
    237                  upper = Decimal("1.0E+310")
    238                  lower = Decimal("1.0E-330")
    239                  if lower < abs(value) < upper :
    240                          # bingo
    241                          return value
    242                  else :
    243                          raise ValueError("Invalid double %s" % v)
    244          except :
    245                  # there was a problem in creating a decimal...
    246                  raise ValueError("Invalid double %s" % v)
    247
    248  # noinspection PyPep8Naming
    249 -def _strToFloat(v):
    250          """Test and convert a float value into Decimal or (python) float. Raises an exception if the number is outside the
    251          permitted range, ie, 1.0E+40 and 1.0E-50. (And these fixed values are the reasons why Decimal is used!)
    252
    253          @param v: the literal string defined as a float
    254          @return Decimal if the local python version is >= 2.4, float otherwise
    255          @raise ValueError: invalid value
    256          """
    257          try :
    258                  value = Decimal(v)
    259                  upper = Decimal("1.0E+40")
    260                  lower = Decimal("1.0E-50")
    261                  if lower < abs(value) < upper :
    262                          # bingo
    263                          return value
    264                  else :
    265                          raise ValueError("Invalid float %s" % v)
    266          except :
    267                  # there was a problem in creating a decimal...
    268                  raise ValueError("Invalid float %s" % v)
    269
    270  #################################### hexa ##################################################
    271  # noinspection PyPep8Naming
    272 -def _strToHexBinary(v):
    273          """Test (and convert) hexa integer values. The number of characters should be even.
    274          @param v: the literal string defined as a hexa number
    275          @return long value
    276          @raise ValueError: invalid value
    277          """
    278          # first of all, the number of characters must be even according to the xsd spec:
    279          length = len(v)
    280          if (length / 2) * 2 != length :
    281                  raise ValueError("Invalid hex binary number %s" % v)
    282          return long(v, 16)
    283
    284  #################################### Datetime, date timestamp, etc ################################
    285
    286  # noinspection PyPep8Naming
    287 -def _strToDateTimeAndStamp(incoming_v, timezone_required=False):
    288          """Test (and convert) datetime and date timestamp values.
    289          @param incoming_v: the literal string defined as the date and time
    290          @param timezone_required: whether the timezone is required (ie, for date timestamp) or not
    291          @return datetime
    292          @rtype: datetime.datetime
    293          @raise ValueError: invalid datetime or date timestamp
    294          """
    295
    296          # First, handle the timezone portion, if there is any
    297          (v, tzone) = _returnTimeZone(incoming_v)
    298
    299          # Check on the timezone. For time date stamp object it is required
    300          if timezone_required and tzone is None :
    301                  raise ValueError("Invalid datetime %s" % incoming_v)
    302
    303          # The microseconds should be handled here...
    304          final_v      = v
    305          milliseconds = 0
    306          milpattern   = "(.*)(\.)([0-9]*)"
    307          match = re.match(milpattern, v)
    308          if match is not None :
    309                  # we have a millisecond portion...
    310                  try :
    311                          final_v = match.groups()[0]
    312                          milliseconds = int(match.groups()[2])
    313                  except :
    314                          raise ValueError("Invalid datetime %s" % incoming_v)
    315          #
    316          # By now, the pattern should be clear
    317          # This may raise an exception...
    318          try :
    319                  tstr = time.strptime(final_v, "%Y-%m-%dT%H:%M:%S")
    320                  if tzone is not None :
    321                          return datetime.datetime(tstr.tm_year, tstr.tm_mon, tstr.tm_mday, tstr.tm_hour, tstr.tm_min, tstr.tm_sec, milliseconds, tzone)
    322                  else :
    323                          return datetime.datetime(tstr.tm_year, tstr.tm_mon, tstr.tm_mday, tstr.tm_hour, tstr.tm_min, tstr.tm_sec, milliseconds)
    324          except :
    325                  raise ValueError("Invalid datetime %s" % incoming_v)
    326
    327  # noinspection PyPep8Naming
    328 -def _strToTime(incoming_v):
    329          """Test (and convert) time values.
    330          @param incoming_v: the literal string defined as time value
    331          @return time
    332          @rtype datetime.time
    333          @raise ValueError: invalid datetime or date timestamp
    334          """
    335
    336          # First, handle the timezone portion, if there is any
    337          (v, tzone) = _returnTimeZone(incoming_v)
    338
    339          # The microseconds should be handled here...
    340          final_v      = v
    341          milliseconds = 0
    342          milpattern   = "(.*)(\.)([0-9]*)"
    343          match = re.match(milpattern, v)
    344          if match is not None:
    345                  # we have a millisecond portion...
    346                  try :
    347                          final_v = match.groups()[0]
    348                          milliseconds = int(match.groups()[2])
    349                  except :
    350                          raise ValueError("Invalid datetime %s" % incoming_v)
    351          #
    352          # By now, the pattern should be clear
    353          # This may raise an exception...
    354          try :
    355                  tstr = time.strptime(final_v,"%H:%M:%S")
    356                  if tzone is not None:
    357                          return datetime.time(tstr.tm_hour, tstr.tm_min, tstr.tm_sec, milliseconds, tzone)
    358                  else :
    359                          return datetime.time(tstr.tm_hour, tstr.tm_min, tstr.tm_sec, milliseconds)
    360          except :
    361                  raise ValueError("Invalid time %s" % incoming_v)
    362
    363  # noinspection PyPep8Naming
    364 -def _strToDate(incoming_v):
    365          """Test (and convert) date values.
    366          @param incoming_v: the literal string defined as date (in iso format)
    367          @return date
    368          @return datetime.date
    369          @raise ValueError: invalid datetime or date timestamp
    370          """
    371
    372          # First, handle the timezone portion, if there is any
    373          (final_v, tzone) = _returnTimeZone(incoming_v)
    374
    375          # This may raise an exception...
    376          try :
    377                  tstr = time.strptime(final_v,"%Y-%m-%d")
    378                  return datetime.date(tstr.tm_year, tstr.tm_mon, tstr.tm_mday)
    379          except :
    380                  raise ValueError("Invalid date %s" % incoming_v)
    381
    382  #################################### The 'g' series for dates ############################
    383  # The 'g' datatypes (eg, gYear) cannot be directly represented as a python datatype
    384  # the series of methods below simply check whether the incoming string is o.k., but the
    385  # returned value is the same as the original
    386  # noinspection PyPep8Naming
    387 -def _strTogYearMonth(v):
    388          """Test gYearMonth value
    389          @param v: the literal string
    390          @return v
    391          @raise ValueError: invalid value
    392          """
    393          try :
    394                  time.strptime(v+"-01", "%Y-%m-%d")
    395                  return v
    396          except :
    397                  raise ValueError("Invalid gYearMonth %s" % v)
    398
    399  # noinspection PyPep8Naming
    400 -def _strTogYear(v) :
    401          """Test gYear value
    402          @param v: the literal string
    403          @return v
    404          @raise ValueError: invalid value
    405          """
    406          try :
    407                  time.strptime(v+"-01-01", "%Y-%m-%d")
    408                  return v
    409          except :
    410                  raise ValueError("Invalid gYear %s" % v)
    411
    412  # noinspection PyPep8Naming
    413 -def _strTogMonthDay(v) :
    414          """Test gYearMonth value
    415          @param v: the literal string
    416          @return v
    417          @raise ValueError: invalid value
    418          """
    419          try :
    420                  time.strptime("2008-" + v, "%Y-%m-%d")
    421                  return v
    422          except :
    423                  raise ValueError("Invalid gMonthDay %s" % v)
    424
    425  # noinspection PyPep8Naming
    426 -def _strTogDay(v):
    427          """Test gYearMonth value
    428          @param v: the literal string
    429          @return v
    430          @raise ValueError: invalid value
    431          """
    432          try :
    433                  time.strptime("2001-01-" + v, "%Y-%m-%d")
    434                  return v
    435          except :
    436                  raise ValueError("Invalid gDay %s" % v)
    437
    438  # noinspection PyPep8Naming
    439 -def _strTogMonth(v):
    440          """Test gYearMonth value
    441          @param v: the literal string
    442          @return v
    443          @raise ValueError: invalid value
    444          """
    445          try :
    446                  time.strptime("2001-" + v + "-01", "%Y-%m-%d")
    447                  return v
    448          except :
    449                  raise ValueError("Invalid gMonth %s" % v)
    450
    451  #################################### XML Literal #########################################
    452  # noinspection PyPep8Naming
    453 -def _strToXMLLiteral(v):
    454          """Test (and convert) XML Literal values.
    455          @param v: the literal string defined as an xml literal
    456          @return the canonical version of the same xml text
    457          @raise ValueError: incorrect xml string
    458          """
    459          import xml.dom.minidom
    460          try :
    461                  dom = xml.dom.minidom.parseString(v)
    462                  return dom.toxml()
    463          except :
    464                  raise ValueError("Invalid XML Literal %s" % v)
    465
    466  #################################### language, NMTOKEN, NAME, etc #########################
    467  #: regular expression for a 'language' datatype
    468  _re_language = "[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*"
    469
    470  #: regexp for NMTOKEN. It must be used with a re.U flag (the '(?U' regexp form did not work. It may depend on the locale...)
    471  _re_NMTOKEN     = "[\w:_.\-]+"
    472
    473  #: characters not permitted at a starting position for Name (otherwise Name is like NMTOKEN
    474  _re_Name_ex             = ['.','-'] + _numb
    475
    476  #: regexp for NCName. It must be used with a re.U flag (the '(?U' regexp form did not work. It may depend on the locale...)
    477  _re_NCName              = "[\w_.\-]+"
    478
    479  #: characters not permitted at a starting position for NCName
    480  _re_NCName_ex   = ['.','-'] + _numb
    481
    482  # noinspection PyDefaultArgument,PyPep8Naming,PyPep8Naming
    483 -def _strToVal_Regexp(v, regexp, flag = 0, excludeStart=[]) :
    484          """Test (and convert) a generic string type, with a check against a regular expression.
    485          @param v: the literal string to be converted
    486          @param regexp: the regular expression to check against
    487          @param flag: flags to be used in the regular expression
    488          @param excludeStart: array of characters disallowed in the first position
    489          @return original string
    490          @raise ValueError: invalid value
    491          """
    492          match = re.match(regexp, v, flag)
    493          if match is None or match.end() != len(v):
    494                  raise ValueError("Invalid literal %s" % v)
    495          else :
    496                  if len(excludeStart) > 0 and v[0] in excludeStart:
    497                          raise ValueError("Invalid literal %s" % v)
    498                  return v
    499
    500  #: Disallowed characters in a token or a normalized string, as a regexp
    501  _re_token = "[^\n\t\r]+"
    502
    503  # noinspection PyPep8Naming
    504 -def _strToToken(v):
    505          """Test (and convert) a string to a token.
    506          @param v: the literal string to be converted
    507          @return original string
    508          @raise ValueError: invalid value
    509          """
    510          if len(v) == 0:
    511                  return v
    512          # filter out the case when there are new lines and similar (if there is a problem, an exception is raised)
    513          _strToVal_Regexp(v, _re_token)
    514          v1 = ' '.join(v.strip().split())
    515          # normalize the string, and see if the result is the same:
    516          if len(v1) == len(v):
    517                  # no characters lost, ie, no unnecessary spaces
    518                  return v
    519          else :
    520                  raise ValueError("Invalid literal %s" % v)
    521
    522  #################################### plain literal ########################################
    523  # noinspection PyPep8Naming
    524 -def _strToPlainLiteral(v):
    525          """Test (and convert) a plain literal
    526          @param v: the literal to be converted
    527          @return a new RDFLib Literal with language tag
    528          @raise ValueError: invalid value
    529          """
    530          reg = "(.*)@([^@]*)"
    531          # a plain literal must match this regexp!
    532          match = re.match(reg,v)
    533          if match is None :
    534                  raise ValueError("Invalid plain literal %s" % v)
    535          else :
    536                  lit  = match.groups()[0]
    537                  if len(match.groups()) == 1 or match.groups()[1] == "" :
    538                          # no language tag
    539                          return Literal(lit)
    540                  else :
    541                          lang = match.groups()[1]
    542                          # check if this is a correct language tag. Note that can raise an exception!
    543                          try :
    544                                  lang = _strToVal_Regexp(lang, _re_language)
    545                                  return Literal(lit,lang=lang.lower())
    546                          except :
    547                                  raise ValueError("Invalid plain literal %s" % v)
    548
    549  #####################################################################################
    550  #: Replacement of RDFLib's conversion function. Each entry assigns a function to an XSD datatype, attempting to convert a string to a Python datatype (or raise an exception if some problem is found)
    551  AltXSDToPYTHON = {
    552          ns_xsd["language"]                              : lambda v: _strToVal_Regexp(v, _re_language),
    553          ns_xsd["NMTOKEN"]                               : lambda v: _strToVal_Regexp(v, _re_NMTOKEN, re.U),
    554          ns_xsd["Name"]                                  : lambda v: _strToVal_Regexp(v, _re_NMTOKEN, re.U, _re_Name_ex),
    555          ns_xsd["NCName"]                                : lambda v: _strToVal_Regexp(v, _re_NCName, re.U, _re_NCName_ex),
    556          ns_xsd["token"]                                 : _strToToken,
    557          ns_rdf["PlainLiteral"]                  : _strToPlainLiteral,
    558          ns_xsd["boolean"]                               : _strToBool,
    559          ns_xsd["decimal"]                               : _strToDecimal,
    560          ns_xsd["anyURI"]                                : _strToAnyURI,
    561          ns_xsd["base64Binary"]                  : _strToBase64Binary,
    562          ns_xsd["double"]                                : _strToDouble,
    563          ns_xsd["float"]                                 : _strToFloat,
    564          ns_xsd["byte"]                                  : lambda v: _strToBoundNumeral(v, _limits_byte, int),
    565          ns_xsd["int"]                                   : lambda v: _strToBoundNumeral(v, _limits_int, long),
    566          ns_xsd["long"]                                  : lambda v: _strToBoundNumeral(v, _limits_long, long),
    567          ns_xsd["positiveInteger"]               : lambda v: _strToBoundNumeral(v, _limits_positiveInteger, long),
    568          ns_xsd["nonPositiveInteger"]    : lambda v: _strToBoundNumeral(v, _limits_nonPositiveInteger, long),
    569          ns_xsd["negativeInteger"]               : lambda v: _strToBoundNumeral(v, _limits_negativeInteger, long),
    570          ns_xsd["nonNegativeInteger"]    : lambda v: _strToBoundNumeral(v, _limits_nonNegativeInteger, long),
    571          ns_xsd["short"]                                 : lambda v: _strToBoundNumeral(v, _limits_short, int),
    572          ns_xsd["unsignedByte"]                  : lambda v: _strToBoundNumeral(v, _limits_unsignedByte, int),
    573          ns_xsd["unsignedShort"]                 : lambda v: _strToBoundNumeral(v, _limits_unsignedShort, int),
    574          ns_xsd["unsignedInt"]                   : lambda v: _strToBoundNumeral(v, _limits_unsignedInt, long),
    575          ns_xsd["unsignedLong"]                  : lambda v: _strToBoundNumeral(v, _limits_unsignedLong, long),
    576          ns_xsd["hexBinary"]                             : _strToHexBinary,
    577          ns_xsd["dateTime"]                              : lambda v: _strToDateTimeAndStamp(v, False),
    578          ns_xsd["dateTimeStamp"]                 : lambda v: _strToDateTimeAndStamp(v, True),
    579          ns_rdf["XMLLiteral"]                    : _strToXMLLiteral,
    580          ns_xsd["integer"]                               : long,
    581          ns_xsd["string"]                                : lambda v: v,
    582          ns_rdf["HTML"]                                  : lambda v: v,
    583          ns_xsd["normalizedString"]              : lambda v: _strToVal_Regexp(v, _re_token),
    584
    585          # These are RDFS specific...
    586          ns_xsd["time"]                                  : _strToTime,
    587          ns_xsd["date"]                                  : _strToDate,
    588          ns_xsd["gYearMonth"]                    : _strTogYearMonth,
    589          ns_xsd["gYear"]                                 : _strTogYear,
    590          ns_xsd["gMonthDay"]                             : _strTogMonthDay,
    591          ns_xsd["gDay"]                                  : _strTogDay,
    592          ns_xsd["gMonth"]                                : _strTogMonth,
    593  }
    594
    595  # noinspection PyPep8Naming
    596 -def use_Alt_lexical_conversions():
    597          """Registering the datatypes item for RDFLib, ie, bind the dictionary values. The 'bind' method of RDFLib adds
    598          extra datatypes to the registered ones in RDFLib, though the table used here (ie, L{AltXSDToPYTHON}) actually overrides
    599          all of the default conversion routines. The method also add a Decimal entry to the PythonToXSD array of RDFLib.
    600          """
    601          _toPythonMapping.update(AltXSDToPYTHON)
    602
    603  # noinspection PyPep8Naming
    604 -def use_RDFLib_lexical_conversions():
    605          """Restore the original (ie, RDFLib) set of lexical conversion routines.
    606          """
    607          _toPythonMapping.update(XSDToPython)
    608
    609  #######################################################################################
    610  # This module can pretty much tested individually...
    611  if __name__ == '__main__' :
    612          import sys
    613          dtype    = sys.argv[1]
    614          string   = sys.argv[2]
    615          datatype = ns_xsd[dtype]
    616          result = AltXSDToPYTHON[datatype](string)
    617          print type(result)
    618          print result
    619