You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
705 lines
34 KiB
705 lines
34 KiB
5 years ago
|
#
|
||
|
# minixsv, Release 0.9.0
|
||
|
# file: xsvalSimpleTypes.py
|
||
|
#
|
||
|
# class for validation of XML schema simple types
|
||
|
#
|
||
|
# history:
|
||
|
# 2004-09-09 rl created
|
||
|
# 2006-08-18 rl W3C testsuite passed for supported features
|
||
|
# 2007-05-24 rl Features for release 0.8 added, some bugs fixed
|
||
|
#
|
||
|
# Copyright (c) 2004-2007 by Roland Leuthe. All rights reserved.
|
||
|
#
|
||
|
# --------------------------------------------------------------------
|
||
|
# The minixsv XML schema validator is
|
||
|
#
|
||
|
# Copyright (c) 2004-2007 by Roland Leuthe
|
||
|
#
|
||
|
# By obtaining, using, and/or copying this software and/or its
|
||
|
# associated documentation, you agree that you have read, understood,
|
||
|
# and will comply with the following terms and conditions:
|
||
|
#
|
||
|
# Permission to use, copy, modify, and distribute this software and
|
||
|
# its associated documentation for any purpose and without fee is
|
||
|
# hereby granted, provided that the above copyright notice appears in
|
||
|
# all copies, and that both that copyright notice and this permission
|
||
|
# notice appear in supporting documentation, and that the name of
|
||
|
# the author not be used in advertising or publicity
|
||
|
# pertaining to distribution of the software without specific, written
|
||
|
# prior permission.
|
||
|
#
|
||
|
# THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||
|
# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
|
||
|
# ABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||
|
# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
|
||
|
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||
|
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||
|
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||
|
# OF THIS SOFTWARE.
|
||
|
# --------------------------------------------------------------------
|
||
|
|
||
|
import sys
|
||
|
import string
|
||
|
import re
|
||
|
import datetime
|
||
|
from decimal import Decimal
|
||
|
from ..genxmlif.xmlifUtils import removeWhitespaces, collapseString, normalizeString, NsNameTupleFactory
|
||
|
from ..minixsv import XSD_NAMESPACE
|
||
|
from xsvalUtils import substituteSpecialEscChars
|
||
|
|
||
|
###################################################
|
||
|
# Validator class for simple types
|
||
|
###################################################
|
||
|
class XsSimpleTypeVal:
|
||
|
|
||
|
def __init__ (self, parent):
|
||
|
self.parent = parent
|
||
|
self.xmlIf = parent.xmlIf
|
||
|
self.xsdNsURI = parent.xsdNsURI
|
||
|
self.xsdIdDict = parent.xsdIdDict
|
||
|
self.xsdIdRefDict = parent.xsdIdRefDict
|
||
|
|
||
|
|
||
|
def unlink (self):
|
||
|
self.parent = None
|
||
|
|
||
|
|
||
|
########################################
|
||
|
# validate given value against simpleType
|
||
|
#
|
||
|
def checkSimpleType (self, inputNode, attrName, typeName, attributeValue, returnDict, idCheck):
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["BaseTypes"].append(str(typeName))
|
||
|
if _suppBaseTypeDict.has_key(typeName):
|
||
|
try:
|
||
|
_suppBaseTypeDict[typeName] (inputNode, typeName, attributeValue, returnDict)
|
||
|
returnDict["primitiveType"] = typeName
|
||
|
except BaseTypeError, errstr:
|
||
|
raise SimpleTypeError("Value of %s (%s) %s" %(repr(attrName), repr(attributeValue), errstr))
|
||
|
|
||
|
elif self.parent.xsdTypeDict.has_key(typeName):
|
||
|
typedefNode = self.parent.xsdTypeDict[typeName]
|
||
|
if typedefNode.getNsName() == (XSD_NAMESPACE, "simpleType"):
|
||
|
self.checkSimpleTypeDef (inputNode, typedefNode, attrName, attributeValue, returnDict, idCheck)
|
||
|
elif (typedefNode.getNsName() == (XSD_NAMESPACE, "complexType") and
|
||
|
typedefNode.getFirstChild().getNsName() == (XSD_NAMESPACE, "simpleContent")):
|
||
|
self.checkSimpleTypeDef (inputNode, typedefNode.getFirstChild(), attrName, attributeValue, returnDict, idCheck)
|
||
|
elif typedefNode.getAttribute("mixed") == "true":
|
||
|
self.checkSimpleType (inputNode, attrName, (XSD_NAMESPACE, "string"), attributeValue, returnDict, idCheck)
|
||
|
elif typeName != (XSD_NAMESPACE, "anyType"):
|
||
|
raise SimpleTypeError("Attribute %s requires a simple type!" %repr(attrName))
|
||
|
|
||
|
if idCheck:
|
||
|
adaptedAttrValue = returnDict["adaptedAttrValue"]
|
||
|
if typeName == (XSD_NAMESPACE, "ID"):
|
||
|
if not self.xsdIdDict.has_key(adaptedAttrValue):
|
||
|
self.xsdIdDict[adaptedAttrValue] = inputNode
|
||
|
else:
|
||
|
raise SimpleTypeError("There are multiple occurences of ID value %s!" %repr(adaptedAttrValue))
|
||
|
if typeName == (XSD_NAMESPACE, "IDREF"):
|
||
|
self.xsdIdRefDict[adaptedAttrValue] = inputNode
|
||
|
else:
|
||
|
# TODO: Fehler im XSD-File => Check muss an anderer Stelle erfolgen
|
||
|
raise SimpleTypeError("%s uses unknown type %s!" %(repr(attrName), repr(typeName)))
|
||
|
|
||
|
|
||
|
########################################
|
||
|
# validate given value against simpleType node
|
||
|
#
|
||
|
def checkSimpleTypeDef (self, inputNode, xsdElement, attrName, attributeValue, returnDict, idCheck):
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
restrictionElement = xsdElement.getFirstChildNS(self.xsdNsURI, "restriction")
|
||
|
extensionElement = xsdElement.getFirstChildNS(self.xsdNsURI, "extension")
|
||
|
listElement = xsdElement.getFirstChildNS(self.xsdNsURI, "list")
|
||
|
unionElement = xsdElement.getFirstChildNS(self.xsdNsURI, "union")
|
||
|
if restrictionElement != None:
|
||
|
self._checkRestrictionTag (inputNode, restrictionElement, attrName, attributeValue, returnDict, idCheck)
|
||
|
if extensionElement != None:
|
||
|
self._checkExtensionTag (inputNode, extensionElement, attrName, attributeValue, returnDict, idCheck)
|
||
|
elif listElement != None:
|
||
|
self._checkListTag (inputNode, listElement, attrName, attributeValue, returnDict, idCheck)
|
||
|
elif unionElement != None:
|
||
|
self._checkUnionTag (inputNode, unionElement, attrName, attributeValue, returnDict, idCheck)
|
||
|
|
||
|
|
||
|
########################################
|
||
|
# validate given value against base type
|
||
|
#
|
||
|
def checkBaseType (self, inputNode, xsdElement, attrName, attributeValue, returnDict, idCheck):
|
||
|
baseType = xsdElement.getQNameAttribute("base")
|
||
|
if baseType != NsNameTupleFactory(None):
|
||
|
self.checkSimpleType (inputNode, attrName, baseType, attributeValue, returnDict, idCheck)
|
||
|
else:
|
||
|
baseTypeNode = xsdElement.getFirstChildNS(self.xsdNsURI, "simpleType")
|
||
|
self.checkSimpleTypeDef (inputNode, baseTypeNode, attrName, attributeValue, returnDict, idCheck)
|
||
|
|
||
|
|
||
|
########################################
|
||
|
# validate given value against restriction node
|
||
|
#
|
||
|
def _checkRestrictionTag (self, inputNode, xsdElement, attrName, attributeValue, returnDict, idCheck):
|
||
|
savedAttrValue = attributeValue
|
||
|
# first check against base type
|
||
|
self.checkBaseType (inputNode, xsdElement, attrName, attributeValue, returnDict, idCheck)
|
||
|
|
||
|
minExcl = xsdElement.getFirstChildNS(self.xsdNsURI, "minExclusive")
|
||
|
minIncl = xsdElement.getFirstChildNS(self.xsdNsURI, "minInclusive")
|
||
|
maxExcl = xsdElement.getFirstChildNS(self.xsdNsURI, "maxExclusive")
|
||
|
maxIncl = xsdElement.getFirstChildNS(self.xsdNsURI, "maxInclusive")
|
||
|
|
||
|
if minExcl != None:
|
||
|
minExclReturnDict = {"BaseTypes":[], "primitiveType":None}
|
||
|
minExclValue = minExcl.getAttribute("value")
|
||
|
self.checkBaseType (inputNode, xsdElement, attrName, minExclValue, minExclReturnDict, idCheck=0)
|
||
|
if returnDict.has_key("orderedValue") and minExclReturnDict.has_key("orderedValue"):
|
||
|
if returnDict["orderedValue"] <= minExclReturnDict["orderedValue"]:
|
||
|
raise SimpleTypeError ("Value of %s (%s) is <= minExclusive (%s)" %(repr(attrName), repr(attributeValue), repr(minExclValue)))
|
||
|
elif minIncl != None:
|
||
|
minInclReturnDict = {"BaseTypes":[], "primitiveType":None}
|
||
|
minInclValue = minIncl.getAttribute("value")
|
||
|
self.checkBaseType (inputNode, xsdElement, attrName, minInclValue, minInclReturnDict, idCheck=0)
|
||
|
if returnDict.has_key("orderedValue") and minInclReturnDict.has_key("orderedValue"):
|
||
|
if returnDict["orderedValue"] < minInclReturnDict["orderedValue"]:
|
||
|
raise SimpleTypeError ("Value of %s (%s) is < minInclusive (%s)" %(repr(attrName), repr(attributeValue), repr(minInclValue)))
|
||
|
if maxExcl != None:
|
||
|
maxExclReturnDict = {"BaseTypes":[], "primitiveType":None}
|
||
|
maxExclValue = maxExcl.getAttribute("value")
|
||
|
self.checkBaseType (inputNode, xsdElement, attrName, maxExclValue, maxExclReturnDict, idCheck=0)
|
||
|
if returnDict.has_key("orderedValue") and maxExclReturnDict.has_key("orderedValue"):
|
||
|
if returnDict["orderedValue"] >= maxExclReturnDict["orderedValue"]:
|
||
|
raise SimpleTypeError ("Value of %s (%s) is >= maxExclusive (%s)" %(repr(attrName), repr(attributeValue), repr(maxExclValue)))
|
||
|
elif maxIncl != None:
|
||
|
maxInclReturnDict = {"BaseTypes":[], "primitiveType":None}
|
||
|
maxInclValue = maxIncl.getAttribute("value")
|
||
|
self.checkBaseType (inputNode, xsdElement, attrName, maxInclValue, maxInclReturnDict, idCheck=0)
|
||
|
if returnDict.has_key("orderedValue") and maxInclReturnDict.has_key("orderedValue"):
|
||
|
if returnDict["orderedValue"] > maxInclReturnDict["orderedValue"]:
|
||
|
raise SimpleTypeError ("Value of %s (%s) is > maxInclusive (%s)" %(repr(attrName), repr(attributeValue), repr(maxInclValue)))
|
||
|
|
||
|
totalDigitsNode = xsdElement.getFirstChildNS(self.xsdNsURI, "totalDigits")
|
||
|
if totalDigitsNode != None:
|
||
|
orderedValueStr = repr(returnDict["orderedValue"])
|
||
|
digits = re.findall("\d" ,orderedValueStr)
|
||
|
if digits[0] == "0" and len(digits) > 1:
|
||
|
digits = digits[1:]
|
||
|
totalDigitsValue = totalDigitsNode.getAttribute("value")
|
||
|
if totalDigitsNode.getAttribute("fixed") == "true":
|
||
|
if len(digits) != string.atoi(totalDigitsValue):
|
||
|
raise SimpleTypeError ("Total number of digits != %s for %s (%s)" %(repr(totalDigitsValue), repr(attrName), repr(attributeValue)))
|
||
|
else:
|
||
|
if len(digits) > string.atoi(totalDigitsValue):
|
||
|
raise SimpleTypeError ("Total number of digits > %s for %s (%s)" %(repr(totalDigitsValue), repr(attrName), repr(attributeValue)))
|
||
|
|
||
|
fractionDigitsNode = xsdElement.getFirstChildNS(self.xsdNsURI, "fractionDigits")
|
||
|
if fractionDigitsNode != None:
|
||
|
orderedValueStr = repr(returnDict["orderedValue"])
|
||
|
fractionDigitsValue = fractionDigitsNode.getAttribute("value")
|
||
|
result = re.search("(?P<intDigits>\d*)(?P<dot>\.)(?P<fracDigits>\d+)", orderedValueStr)
|
||
|
if result != None:
|
||
|
numberOfFracDigits = len (result.group('fracDigits'))
|
||
|
else:
|
||
|
numberOfFracDigits = 0
|
||
|
if fractionDigitsNode.getAttribute("fixed") == "true" and numberOfFracDigits != string.atoi(fractionDigitsValue):
|
||
|
raise SimpleTypeError ("Fraction number of digits != %s for %s (%s)" %(repr(fractionDigitsValue), repr(attrName), repr(attributeValue)))
|
||
|
elif numberOfFracDigits > string.atoi(fractionDigitsValue):
|
||
|
raise SimpleTypeError ("Fraction number of digits > %s for %s (%s)" %(repr(fractionDigitsValue), repr(attrName), repr(attributeValue)))
|
||
|
|
||
|
if returnDict.has_key("length"):
|
||
|
lengthNode = xsdElement.getFirstChildNS(self.xsdNsURI, "length")
|
||
|
if lengthNode != None:
|
||
|
length = string.atoi(lengthNode.getAttribute("value"))
|
||
|
if returnDict["length"] != length:
|
||
|
raise SimpleTypeError ("Length of %s (%s) must be %d!" %(repr(attrName), repr(attributeValue), length))
|
||
|
minLengthNode = xsdElement.getFirstChildNS(self.xsdNsURI, "minLength")
|
||
|
if minLengthNode != None:
|
||
|
minLength = string.atoi(minLengthNode.getAttribute("value"))
|
||
|
if returnDict["length"] < minLength:
|
||
|
raise SimpleTypeError ("Length of %s (%s) must be >= %d!" %(repr(attrName), repr(attributeValue), minLength))
|
||
|
maxLengthNode = xsdElement.getFirstChildNS(self.xsdNsURI, "maxLength")
|
||
|
if maxLengthNode != None:
|
||
|
maxLength = string.atoi(maxLengthNode.getAttribute("value"))
|
||
|
if returnDict["length"] > maxLength:
|
||
|
raise SimpleTypeError ("Length of %s (%s) must be <= %d!" %(repr(attrName), repr(attributeValue), maxLength))
|
||
|
|
||
|
whiteSpace = xsdElement.getFirstChildNS(self.xsdNsURI, "whiteSpace")
|
||
|
if whiteSpace != None:
|
||
|
returnDict["wsAction"] = whiteSpace.getAttribute("value")
|
||
|
if returnDict["wsAction"] == "replace":
|
||
|
normalizedValue = normalizeString(attributeValue)
|
||
|
if normalizedValue != attributeValue:
|
||
|
returnDict["adaptedAttrValue"] = normalizedValue
|
||
|
elif returnDict["wsAction"] == "collapse":
|
||
|
collapsedValue = collapseString(attributeValue)
|
||
|
if collapsedValue != attributeValue:
|
||
|
returnDict["adaptedAttrValue"] = collapsedValue
|
||
|
|
||
|
enumerationElementList = xsdElement.getChildrenNS(self.xsdNsURI, "enumeration")
|
||
|
if enumerationElementList != []:
|
||
|
if returnDict.has_key("orderedValue"):
|
||
|
attributeValue = returnDict["orderedValue"]
|
||
|
elif returnDict.has_key("adaptedAttrValue"):
|
||
|
attributeValue = returnDict["adaptedAttrValue"]
|
||
|
|
||
|
for enumeration in enumerationElementList:
|
||
|
enumReturnDict = {"BaseTypes":[], "primitiveType":None}
|
||
|
enumValue = enumeration["value"]
|
||
|
self.checkBaseType (inputNode, xsdElement, attrName, enumValue, enumReturnDict, idCheck=0)
|
||
|
if enumReturnDict.has_key("orderedValue"):
|
||
|
enumValue = enumReturnDict["orderedValue"]
|
||
|
elif enumReturnDict.has_key("adaptedAttrValue"):
|
||
|
enumValue = enumReturnDict["adaptedAttrValue"]
|
||
|
|
||
|
if enumValue == attributeValue:
|
||
|
break
|
||
|
else:
|
||
|
raise SimpleTypeError ("Enumeration value %s not allowed!" %repr(attributeValue))
|
||
|
|
||
|
|
||
|
if returnDict.has_key("adaptedAttrValue"):
|
||
|
attributeValue = returnDict["adaptedAttrValue"]
|
||
|
|
||
|
patternMatch = 1
|
||
|
notMatchedPatternList = []
|
||
|
for patternNode in xsdElement.getChildrenNS(self.xsdNsURI, "pattern"):
|
||
|
rePattern = patternNode.getAttribute("value")
|
||
|
intRePattern = rePattern
|
||
|
try:
|
||
|
intRePattern = substituteSpecialEscChars (intRePattern)
|
||
|
except SyntaxError, errInst:
|
||
|
raise SimpleTypeError, str(errInst)
|
||
|
patternMatch = self._matchesPattern (intRePattern, attributeValue)
|
||
|
|
||
|
if patternMatch:
|
||
|
break
|
||
|
else:
|
||
|
notMatchedPatternList.append(rePattern)
|
||
|
|
||
|
if not patternMatch:
|
||
|
try:
|
||
|
pattern = " nor ".join(notMatchedPatternList)
|
||
|
except:
|
||
|
pattern = ""
|
||
|
raise SimpleTypeError ("Value of attribute %s (%s) does not match pattern %s!" %(repr(attrName), repr(attributeValue), repr(pattern)))
|
||
|
|
||
|
|
||
|
########################################
|
||
|
# checks if 'value' matches 'rePattern' completely
|
||
|
#
|
||
|
def _matchesPattern (self, intRePattern, attributeValue):
|
||
|
completePatternMatch = 0
|
||
|
try:
|
||
|
regexObj = re.match(intRePattern, attributeValue, re.U)
|
||
|
if regexObj and regexObj.end() == len(attributeValue):
|
||
|
completePatternMatch = 1
|
||
|
except Exception:
|
||
|
pass
|
||
|
return completePatternMatch
|
||
|
|
||
|
|
||
|
########################################
|
||
|
# validate given value against list node
|
||
|
#
|
||
|
def _checkListTag (self, inputNode, xsdElement, attrName, attributeValue, returnDict, idCheck):
|
||
|
if attributeValue != "":
|
||
|
itemType = xsdElement.getQNameAttribute ("itemType")
|
||
|
# substitute multiple whitespace characters by a single ' '
|
||
|
collapsedValue = collapseString(attributeValue)
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
returnDict["adaptedAttrValue"] = collapsedValue
|
||
|
|
||
|
# divide up attributeValue => store it into list
|
||
|
attributeList = string.split(collapsedValue, " ")
|
||
|
for attrValue in attributeList:
|
||
|
elementReturnDict = {"BaseTypes":[], "primitiveType":None}
|
||
|
if itemType != (None, None):
|
||
|
self.checkSimpleType (inputNode, attrName, itemType, attrValue, elementReturnDict, idCheck)
|
||
|
else:
|
||
|
itemTypeNode = xsdElement.getFirstChildNS(self.xsdNsURI, "simpleType")
|
||
|
self.checkSimpleTypeDef (inputNode, itemTypeNode, attrName, attrValue, elementReturnDict, idCheck)
|
||
|
|
||
|
returnDict["BaseTypes"].extend(elementReturnDict["BaseTypes"])
|
||
|
returnDict["length"] = len(attributeList)
|
||
|
else:
|
||
|
returnDict["length"] = 0
|
||
|
|
||
|
|
||
|
########################################
|
||
|
# validate given value against extension node
|
||
|
#
|
||
|
def _checkExtensionTag (self, inputNode, xsdElement, attrName, attributeValue, returnDict, idCheck):
|
||
|
# first check against base type
|
||
|
self.checkBaseType (inputNode, xsdElement, attrName, attributeValue, returnDict, idCheck)
|
||
|
|
||
|
|
||
|
########################################
|
||
|
# validate given value against union node
|
||
|
#
|
||
|
def _checkUnionTag (self, inputNode, xsdElement, attrName, attributeValue, returnDict, idCheck):
|
||
|
memberTypes = xsdElement.getAttribute ("memberTypes")
|
||
|
if memberTypes != None:
|
||
|
# substitute multiple whitespace characters by a single ' '
|
||
|
# divide up attributeValue => store it into list
|
||
|
for memberType in string.split(collapseString(memberTypes), " "):
|
||
|
try:
|
||
|
self.checkSimpleType (inputNode, attrName, xsdElement.qName2NsName(memberType, useDefaultNs=1), attributeValue, returnDict, idCheck)
|
||
|
return
|
||
|
except SimpleTypeError, errstr:
|
||
|
pass
|
||
|
|
||
|
# memberTypes and additional type definitions is legal!
|
||
|
for childSimpleType in xsdElement.getChildrenNS(self.xsdNsURI, "simpleType"):
|
||
|
try:
|
||
|
self.checkSimpleTypeDef (inputNode, childSimpleType, attrName, attributeValue, returnDict, idCheck)
|
||
|
return
|
||
|
except SimpleTypeError, errstr:
|
||
|
pass
|
||
|
|
||
|
raise SimpleTypeError ("%s (%s) is no valid union member type!" %(repr(attrName), repr(attributeValue)))
|
||
|
|
||
|
|
||
|
###############################################################
|
||
|
# Base type check functions
|
||
|
###############################################################
|
||
|
|
||
|
reDecimal = re.compile("[+-]?[0-9]*\.?[0-9]+", re.U)
|
||
|
reInteger = re.compile("[+-]?[0-9]+", re.U)
|
||
|
reDouble = re.compile("([+-]?[0-9]*\.?[0-9]+([eE][+\-]?[0-9]+)?)|INF|-INF|NaN", re.U)
|
||
|
reHexBinary = re.compile("([a-fA-F0-9]{2})*", re.U)
|
||
|
reBase64Binary = re.compile("(?P<validBits>[a-zA-Z0-9+/]*)={0,3}", re.U)
|
||
|
reQName = re.compile(substituteSpecialEscChars("\i\c*"), re.U)
|
||
|
reDuration = re.compile("-?P(?P<years>\d+Y)?(?P<months>\d+M)?(?P<days>\d+D)?(T(?P<hours>\d+H)?(?P<minutes>\d+M)?((?P<seconds>\d+)(?P<fracsec>\.\d+)?S)?)?", re.U)
|
||
|
|
||
|
reDateTime = re.compile("(?P<date>\d{4}-\d{2}-\d{2})T(?P<time>\d{2}:\d{2}:\d{2}(\.\d+)?)(?P<offset>Z|[+-]\d{2}:\d{2})?", re.U)
|
||
|
reDate = re.compile("\d{4}-\d{2}-\d{2}(?P<offset>Z|[+-]\d{2}:\d{2})?", re.U)
|
||
|
reTime = re.compile("(?P<time>\d{2}:\d{2}:\d{2})(?P<fracsec>\.\d+)?(?P<offset>Z|[+-]\d{2}:\d{2})?", re.U)
|
||
|
reYearMonth = re.compile("\d{4}-\d{2}(?P<offset>Z|[+-]\d{2}:\d{2})?", re.U)
|
||
|
reMonthDay = re.compile("--\d{2}-\d{2}(?P<offset>Z|[+-]\d{2}:\d{2})?", re.U)
|
||
|
reYear = re.compile("(?P<year>\d{1,4})(?P<offset>Z|[+-]\d{2}:\d{2})?", re.U)
|
||
|
reMonth = re.compile("--\d{2}(--)?(?P<offset>Z|[+-]\d{2}:\d{2})?", re.U)
|
||
|
reDay = re.compile("---\d{2}(?P<offset>Z|[+-]\d{2}:\d{2})?", re.U)
|
||
|
|
||
|
|
||
|
def _checkAnySimpleType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
# TODO: Nothing to check??
|
||
|
returnDict["length"] = len(attributeValue)
|
||
|
|
||
|
def _checkStringType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
# TODO: all valid??
|
||
|
returnDict["length"] = len(attributeValue)
|
||
|
|
||
|
def _checkAnyUriType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
# TODO: any checks??
|
||
|
if attributeValue[0:2] == '##':
|
||
|
raise BaseTypeError("is not a valid URI!")
|
||
|
returnDict["adaptedAttrValue"] = collapseString(attributeValue)
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
returnDict["length"] = len(attributeValue)
|
||
|
|
||
|
def _checkDecimalType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
regexObj = reDecimal.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue):
|
||
|
raise BaseTypeError("is not a decimal value!")
|
||
|
try:
|
||
|
value = Decimal(attributeValue)
|
||
|
returnDict["orderedValue"] = value.normalize()
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
except:
|
||
|
raise BaseTypeError("is not a decimal value!")
|
||
|
|
||
|
|
||
|
def _checkIntegerType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
regexObj = reInteger.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue):
|
||
|
raise BaseTypeError("is not an integer value!")
|
||
|
try:
|
||
|
returnDict["orderedValue"] = Decimal(attributeValue)
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
except:
|
||
|
raise BaseTypeError("is out of range for validation!")
|
||
|
|
||
|
|
||
|
def _checkFloatType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
if attributeValue not in ("INF", "-INF", "NaN"):
|
||
|
try:
|
||
|
value = float(attributeValue)
|
||
|
returnDict["orderedValue"] = value
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
except:
|
||
|
raise BaseTypeError("is not a float value!")
|
||
|
|
||
|
def _checkDoubleType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
regexObj = reDouble.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue):
|
||
|
raise BaseTypeError("is not a double value!")
|
||
|
try:
|
||
|
value = Decimal(attributeValue)
|
||
|
returnDict["orderedValue"] = value.normalize()
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
except:
|
||
|
raise BaseTypeError("is not a double value!")
|
||
|
|
||
|
def _checkHexBinaryType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = removeWhitespaces(attributeValue)
|
||
|
regexObj = reHexBinary.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue):
|
||
|
raise BaseTypeError("is not a hexBinary value (each byte is represented by 2 characters)!")
|
||
|
returnDict["length"] = len(attributeValue) / 2
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
|
||
|
def _checkBase64BinaryType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
regexObj = reBase64Binary.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue):
|
||
|
raise BaseTypeError("is not a base64Binary value (6 bits are represented by 1 character)!")
|
||
|
returnDict["length"] = (len(regexObj.group("validBits")) * 6) / 8
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
|
||
|
def _checkBooleanType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
if attributeValue not in ("true", "false", "1", "0"):
|
||
|
raise BaseTypeError("is not a boolean value!")
|
||
|
if attributeValue in ("true", "1"):
|
||
|
returnDict["orderedValue"] = "__BOOLEAN_TRUE__"
|
||
|
else:
|
||
|
returnDict["orderedValue"] = "__BOOLEAN_FALSE__"
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
|
||
|
def _checkQNameType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
regexObj = reQName.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue):
|
||
|
raise BaseTypeError("is not a QName!")
|
||
|
|
||
|
try:
|
||
|
inputNode.getNamespace(attributeValue)
|
||
|
except LookupError:
|
||
|
raise BaseTypeError("is not a valid QName (namespace prefix unknown)!")
|
||
|
|
||
|
returnDict["length"] = len(attributeValue)
|
||
|
returnDict["orderedValue"] = inputNode.qName2NsName(attributeValue, useDefaultNs=1)
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
|
||
|
def _checkDurationType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
regexObj = reDuration.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue) or attributeValue[-1] == "T" or attributeValue[-1] == "P":
|
||
|
raise BaseTypeError("is not a valid duration value!")
|
||
|
sign = ""
|
||
|
if attributeValue[0] == "-": sign = "-"
|
||
|
days = 0
|
||
|
seconds = 0
|
||
|
microseconds = 0
|
||
|
if regexObj.group("years") != None:
|
||
|
days = days + (int(sign + regexObj.group("years")[:-1]) * 365)
|
||
|
if regexObj.group("months") != None:
|
||
|
days = days + (int(sign + regexObj.group("months")[:-1]) * 30)
|
||
|
if regexObj.group("days") != None:
|
||
|
days = days + int(sign + regexObj.group("days")[:-1])
|
||
|
if regexObj.group("hours") != None:
|
||
|
seconds = seconds + int(sign + regexObj.group("hours")[:-1]) * 3600
|
||
|
if regexObj.group("minutes") != None:
|
||
|
seconds = seconds + (int(sign + regexObj.group("minutes")[:-1]) * 60)
|
||
|
if regexObj.group("seconds") != None:
|
||
|
seconds = seconds + int(sign + regexObj.group("seconds"))
|
||
|
if regexObj.group("fracsec") != None:
|
||
|
microseconds = int(Decimal(sign + regexObj.group("fracsec")) * 1000000)
|
||
|
try:
|
||
|
timeDeltaObj = datetime.timedelta(days=days, seconds=seconds, microseconds=microseconds)
|
||
|
except ValueError, errstr:
|
||
|
raise BaseTypeError("is invalid (%s)!" %(errstr))
|
||
|
returnDict["orderedValue"] = timeDeltaObj
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
|
||
|
def _checkDateTimeType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
regexObj = reDateTime.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue):
|
||
|
raise BaseTypeError("is not a dateTime value!")
|
||
|
date = regexObj.group("date")
|
||
|
time = regexObj.group("time")
|
||
|
offset = regexObj.group("offset")
|
||
|
try:
|
||
|
if offset != None:
|
||
|
tz = TimezoneFixedOffset(offset)
|
||
|
else:
|
||
|
tz = None
|
||
|
dtObj = datetime.datetime(int(date[0:4]),int(date[5:7]),int(date[8:10]),
|
||
|
int(time[0:2]),int(time[3:5]),int(time[6:8]), 0, tz)
|
||
|
except ValueError, errstr:
|
||
|
raise BaseTypeError("is invalid (%s)!" %(errstr))
|
||
|
returnDict["orderedValue"] = dtObj
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
|
||
|
def _checkDateType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
regexObj = reDate.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue):
|
||
|
raise BaseTypeError("is not a date value!")
|
||
|
try:
|
||
|
dateObj = datetime.date(int(attributeValue[0:4]),int(attributeValue[5:7]),int(attributeValue[8:10]))
|
||
|
except ValueError, errstr:
|
||
|
raise BaseTypeError("is invalid (%s)!" %(errstr))
|
||
|
returnDict["orderedValue"] = dateObj
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
|
||
|
def _checkTimeType (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
regexObj = reTime.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue):
|
||
|
raise BaseTypeError("is not a time value!")
|
||
|
time = regexObj.group("time")
|
||
|
fracsec = regexObj.group("fracsec")
|
||
|
offset = regexObj.group("offset")
|
||
|
try:
|
||
|
if offset != None:
|
||
|
tz = TimezoneFixedOffset(offset)
|
||
|
else:
|
||
|
tz = None
|
||
|
if fracsec != None:
|
||
|
fracSec = int(fracsec[1:])
|
||
|
else:
|
||
|
fracSec = 0
|
||
|
timeObj = datetime.time(int(time[0:2]),int(time[3:5]),int(time[6:8]), fracSec, tz)
|
||
|
except ValueError, errstr:
|
||
|
raise BaseTypeError("is invalid (%s)!" %(errstr))
|
||
|
returnDict["orderedValue"] = timeObj
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
|
||
|
def _checkYearMonth (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
regexObj = reYearMonth.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue):
|
||
|
raise BaseTypeError("is not a gYearMonth value!")
|
||
|
try:
|
||
|
dateObj = datetime.date(int(attributeValue[0:4]),int(attributeValue[5:7]),1)
|
||
|
except ValueError, errstr:
|
||
|
raise BaseTypeError("is invalid (%s)!" %(errstr))
|
||
|
returnDict["orderedValue"] = dateObj
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
|
||
|
def _checkMonthDay (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
regexObj = reMonthDay.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue):
|
||
|
raise BaseTypeError("is not a gMonthDay value!")
|
||
|
try:
|
||
|
dateObj = datetime.date(2004, int(attributeValue[2:4]),int(attributeValue[5:7]))
|
||
|
except ValueError, errstr:
|
||
|
raise BaseTypeError("is invalid (%s)!" %(errstr))
|
||
|
returnDict["orderedValue"] = dateObj
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
|
||
|
def _checkYear (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
regexObj = reYear.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue or regexObj.group("year") == None):
|
||
|
raise BaseTypeError("is not a gYear value (1)!")
|
||
|
try:
|
||
|
year = int(regexObj.group("year"))
|
||
|
if year < 1 or year > 9999:
|
||
|
raise BaseTypeError("is not a valid gYear value!")
|
||
|
except:
|
||
|
raise BaseTypeError("is not a gYear value!")
|
||
|
returnDict["orderedValue"] = year
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
|
||
|
def _checkMonth (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
regexObj = reMonth.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue):
|
||
|
raise BaseTypeError("is not a gMonth value!")
|
||
|
month = int(attributeValue[2:4])
|
||
|
if month < 1 or month > 12:
|
||
|
raise BaseTypeError("is invalid (month must be in 1..12)!")
|
||
|
returnDict["orderedValue"] = month
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
|
||
|
def _checkDay (inputNode, simpleType, attributeValue, returnDict):
|
||
|
attributeValue = collapseString(attributeValue)
|
||
|
regexObj = reDay.match(attributeValue)
|
||
|
if not regexObj or regexObj.end() != len(attributeValue):
|
||
|
raise BaseTypeError("is not a gDay value!")
|
||
|
day = int(attributeValue[3:5])
|
||
|
if day < 1 or day > 31:
|
||
|
raise BaseTypeError("is invalid (day must be in 1..31)!")
|
||
|
returnDict["orderedValue"] = day
|
||
|
returnDict["adaptedAttrValue"] = attributeValue
|
||
|
returnDict["wsAction"] = "collapse"
|
||
|
|
||
|
########################################
|
||
|
# timezone class
|
||
|
#
|
||
|
class TimezoneFixedOffset(datetime.tzinfo):
|
||
|
def __init__(self, offset):
|
||
|
if offset == "Z":
|
||
|
self.__offset = datetime.timedelta(0)
|
||
|
else:
|
||
|
self.__offset = datetime.timedelta(hours=int(offset[0:3]),
|
||
|
minutes=int(offset[0] + offset[4:5]))
|
||
|
|
||
|
def utcoffset(self, dt):
|
||
|
return self.__offset
|
||
|
def tzname(self, dt):
|
||
|
return None
|
||
|
|
||
|
def dst(self, dt):
|
||
|
return datetime.timedelta(0)
|
||
|
|
||
|
########################################
|
||
|
# define own exception for XML schema validation errors
|
||
|
#
|
||
|
class SimpleTypeError (StandardError):
|
||
|
pass
|
||
|
|
||
|
class BaseTypeError (StandardError):
|
||
|
pass
|
||
|
|
||
|
|
||
|
########################################
|
||
|
# Base type dictionaries
|
||
|
#
|
||
|
_suppBaseTypeDict = {(XSD_NAMESPACE, "anySimpleType"): _checkAnySimpleType,
|
||
|
(XSD_NAMESPACE, "string"): _checkStringType,
|
||
|
(XSD_NAMESPACE, "anyURI"): _checkAnyUriType,
|
||
|
(XSD_NAMESPACE, "decimal"): _checkDecimalType,
|
||
|
(XSD_NAMESPACE, "integer"): _checkIntegerType,
|
||
|
(XSD_NAMESPACE, "float"): _checkFloatType,
|
||
|
(XSD_NAMESPACE, "double"): _checkDoubleType,
|
||
|
(XSD_NAMESPACE, "hexBinary"): _checkHexBinaryType,
|
||
|
(XSD_NAMESPACE, "base64Binary"): _checkBase64BinaryType,
|
||
|
(XSD_NAMESPACE, "boolean"): _checkBooleanType,
|
||
|
(XSD_NAMESPACE, "QName"): _checkQNameType,
|
||
|
(XSD_NAMESPACE, "NOTATION"): _checkQNameType,
|
||
|
(XSD_NAMESPACE, "duration"): _checkDurationType,
|
||
|
(XSD_NAMESPACE, "dateTime"): _checkDateTimeType,
|
||
|
(XSD_NAMESPACE, "date"): _checkDateType,
|
||
|
(XSD_NAMESPACE, "time"): _checkTimeType,
|
||
|
(XSD_NAMESPACE, "gYearMonth"): _checkYearMonth,
|
||
|
(XSD_NAMESPACE, "gMonthDay"): _checkMonthDay,
|
||
|
(XSD_NAMESPACE, "gYear"): _checkYear,
|
||
|
(XSD_NAMESPACE, "gMonth"): _checkMonth,
|
||
|
(XSD_NAMESPACE, "gDay"): _checkDay,
|
||
|
}
|
||
|
|