--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/minixsv/xsvalSimpleTypes.py Wed Jan 31 16:31:39 2007 +0100
@@ -0,0 +1,332 @@
+#
+# # minixsv, Release 0.3
+# file: xsvalSimpleTypes.py
+#
+# class for validation of XML schema simple types
+#
+# history:
+# 2004-09-09 rl created
+#
+# Copyright (c) 2004 by Roland Leuthe. All rights reserved.
+#
+# --------------------------------------------------------------------
+# The minixsv XML schema validator is
+#
+# Copyright (c) 2004 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
+
+
+class XsSimpleTypeVal:
+
+ def __init__ (self, parent):
+ self.parent = parent
+ self.xmlIf = parent.xmlIf
+ self.xsdNSAlias = parent.xsdNSAlias
+ self.xsdTree = parent.xsdTree
+
+
+ ########################################
+ # validate given value against simpleType
+ #
+ def checkSimpleType (self, attrName, typeName, attributeValue, returnDict):
+ localTypeName = self.xmlIf.extractLocalName(typeName)
+ if self.parent.xsdTypeDict.has_key(localTypeName):
+ typedefNode = self.parent.xsdTypeDict[localTypeName]
+ if typedefNode.getTagName () == self.xsdNSAlias + "simpleType":
+ self.checkSimpleTypeDef (typedefNode, attrName, attributeValue, returnDict)
+ else:
+ raise SimpleTypeError("Type '%s' must be simple type!" %(typeName))
+ else:
+ try:
+ validateBaseType (typeName, attributeValue, returnDict)
+ except BaseTypeError, errstr:
+ raise SimpleTypeError("Value of '%s' (%s) %s" %(attrName, attributeValue, errstr))
+
+
+ ########################################
+ # validate given value against simpleType node
+ #
+ def checkSimpleTypeDef (self, xsdElement, attrName, attributeValue, returnDict):
+ restrictionElement = xsdElement.getFirstChildNS(self.xsdNSAlias, "restriction")
+ listElement = xsdElement.getFirstChildNS(self.xsdNSAlias, "list")
+ unionElement = xsdElement.getFirstChildNS(self.xsdNSAlias, "union")
+ if restrictionElement != None:
+ self._checkRestrictionTag (restrictionElement, attrName, attributeValue, returnDict)
+ elif listElement != None:
+ self._checkListTag (listElement, attrName, attributeValue, returnDict)
+ elif unionElement != None:
+ self._checkUnionTag (unionElement, attrName, attributeValue, returnDict)
+
+ ########################################
+ # validate given value against restriction node
+ #
+ def _checkRestrictionTag (self, xsdElement, attrName, attributeValue, returnDict):
+ # first check against base type
+ baseType = xsdElement.getAttribute("base")
+ if baseType != None:
+ self.checkSimpleType (attrName, baseType, attributeValue, returnDict)
+ else:
+ baseTypeNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "simpleType")
+ self.checkSimpleTypeDef (baseTypeNode, attrName, attributeValue, returnDict)
+
+ minExcl = xsdElement.getFirstChildNS(self.xsdNSAlias, "minExclusive")
+ minIncl = xsdElement.getFirstChildNS(self.xsdNSAlias, "minInclusive")
+ maxExcl = xsdElement.getFirstChildNS(self.xsdNSAlias, "maxExclusive")
+ maxIncl = xsdElement.getFirstChildNS(self.xsdNSAlias, "maxInclusive")
+
+ if minExcl != None:
+ minExclReturnDict = {}
+ minExclValue = minExcl.getAttribute("value")
+ self.checkSimpleType (attrName, baseType, minExclValue, minExclReturnDict)
+ if returnDict.has_key("orderedValue") and minExclReturnDict.has_key("orderedValue"):
+ if returnDict["orderedValue"] <= minExclReturnDict["orderedValue"]:
+ raise SimpleTypeError ("Value of %s (%s) is <= minExclusive (%s)" %(attrName, attributeValue, minExclValue))
+ elif minIncl != None:
+ minInclReturnDict = {}
+ minInclValue = minIncl.getAttribute("value")
+ self.checkSimpleType (attrName, baseType, minInclValue, minInclReturnDict)
+ if returnDict.has_key("orderedValue") and minInclReturnDict.has_key("orderedValue"):
+ if returnDict["orderedValue"] < minInclReturnDict["orderedValue"]:
+ raise SimpleTypeError ("Value of %s (%s) is < minInclusive (%s)" %(attrName, attributeValue, minInclValue))
+ if maxExcl != None:
+ maxExclReturnDict = {}
+ maxExclValue = maxExcl.getAttribute("value")
+ self.checkSimpleType (attrName, baseType, maxExclValue, maxExclReturnDict)
+ if returnDict.has_key("orderedValue") and maxExclReturnDict.has_key("orderedValue"):
+ if returnDict["orderedValue"] >= maxExclReturnDict["orderedValue"]:
+ raise SimpleTypeError ("Value of %s (%s) is >= maxExclusive (%s)" %(attrName, attributeValue, maxExclValue))
+ elif maxIncl != None:
+ maxInclReturnDict = {}
+ maxInclValue = maxIncl.getAttribute("value")
+ self.checkSimpleType (attrName, baseType, maxInclValue, maxInclReturnDict)
+ if returnDict.has_key("orderedValue") and maxInclReturnDict.has_key("orderedValue"):
+ if returnDict["orderedValue"] > maxInclReturnDict["orderedValue"]:
+ raise SimpleTypeError ("Value of %s (%s) is > maxInclusive (%s)" %(attrName, attributeValue, maxInclValue))
+
+ totalDigitsNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "totalDigits")
+ if totalDigitsNode != None:
+ totalDigitsValue = totalDigitsNode.getAttribute("value")
+ if totalDigitsNode.getAttribute("fixed") == "true":
+ if len(re.findall("\d" ,attributeValue)) != string.atoi(totalDigitsValue):
+ raise SimpleTypeError ("Total number of digits != %s for %s (%s)" %(totalDigitsValue, attrName, attributeValue))
+ else:
+ if len(re.findall("\d" ,attributeValue)) > string.atoi(totalDigitsValue):
+ raise SimpleTypeError ("Total number of digits > %s for %s (%s)" %(totalDigitsValue, attrName, attributeValue))
+ fractionDigitsNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "fractionDigits")
+ if fractionDigitsNode != None:
+ fractionDigitsValue = fractionDigitsNode.getAttribute("value")
+ result = re.search("(?P<intDigits>\d+)(?P<dot>\.)(?P<fracDigits>\d+)" ,attributeValue)
+ 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)" %(fractionDigitsValue, attrName, attributeValue))
+ elif numberOfFracDigits > string.atoi(fractionDigitsValue):
+ raise SimpleTypeError ("Fraction number of digits > %s for %s (%s)" %(fractionDigitsValue, attrName, attributeValue))
+
+ if returnDict.has_key("length"):
+ lengthNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "length")
+ if lengthNode != None:
+ length = string.atoi(lengthNode.getAttribute("value"))
+ if returnDict["length"] != length:
+ raise SimpleTypeError ("Length of %s (%s) must be %d!" %(attrName, attributeValue, length))
+ minLengthNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "minLength")
+ if minLengthNode != None:
+ minLength = string.atoi(minLengthNode.getAttribute("value"))
+ if returnDict["length"] < minLength:
+ raise SimpleTypeError ("Length of %s (%s) must be >= %d!" %(attrName, attributeValue, minLength))
+ maxLengthNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "maxLength")
+ if maxLengthNode != None:
+ maxLength = string.atoi(maxLengthNode.getAttribute("value"))
+ if returnDict["length"] > maxLength:
+ raise SimpleTypeError ("Length of %s (%s) must be <= %d!" %(attrName, attributeValue, maxLength))
+
+ enumerationElementList = xsdElement.getChildrenNS(self.xsdNSAlias, "enumeration")
+ if enumerationElementList != []:
+ for enumeration in enumerationElementList:
+ if enumeration.getAttribute ("value") == attributeValue:
+ break
+ else:
+ raise SimpleTypeError ("Enumeration value '%s' not allowed!" %(attributeValue))
+
+ patternNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "pattern")
+ if patternNode != None:
+ rePattern = patternNode.getAttribute("value")
+ regexObj = re.match(rePattern, attributeValue)
+ if not regexObj or regexObj.end() != len(attributeValue):
+ raise SimpleTypeError ("Attribute value '%s' does not match pattern '%s'!" %(attributeValue, rePattern))
+
+ whiteSpace = xsdElement.getFirstChildNS(self.xsdNSAlias, "whiteSpace")
+ if whiteSpace != None:
+ wsAction = whiteSpace.getAttribute("value")
+ if wsAction == "replace":
+ normalizedValue = self._normalizeString(attributeValue)
+ if normalizedValue != attributeValue:
+ returnDict["adaptedAttrValue"] = normalizedValue
+ elif wsAction == "collapse":
+ collapsedValue = self._collapseString(attributeValue)
+ if collapsedValue != attributeValue:
+ returnDict["adaptedAttrValue"] = collapsedValue
+
+
+ ########################################
+ # validate given value against list node
+ #
+ def _checkListTag (self, xsdElement, attrName, attributeValue, returnDict):
+ if attributeValue != "":
+ itemType = xsdElement.getAttribute ("itemType")
+ # substitute multiple whitespace characters by a single ' '
+ collapsedValue = self._collapseString(attributeValue)
+ if collapsedValue != attributeValue:
+ returnDict["adaptedAttrValue"] = collapsedValue
+
+ # divide up attributeValue => store it into list
+ attributeList = string.split(collapsedValue, " ")
+ for attrValue in attributeList:
+ elementReturnDict = {}
+ if itemType != None:
+ self.checkSimpleType (attrName, itemType, attrValue, elementReturnDict)
+ else:
+ itemTypeNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "simpleType")
+ self.checkSimpleTypeDef (itemTypeNode, attrName, attrValue, elementReturnDict)
+
+ returnDict["length"] = len(attributeList)
+ else:
+ returnDict["length"] = 0
+
+
+ ########################################
+ # validate given value against union node
+ #
+ def _checkUnionTag (self, xsdElement, attrName, attributeValue, returnDict):
+ 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(self._collapseString(memberTypes), " "):
+ try:
+ self.checkSimpleType (attrName, memberType, attributeValue, returnDict)
+ return
+ except SimpleTypeError, errstr:
+ pass
+
+ # memberTypes and additional type definitions is legal!
+ for childSimpleType in xsdElement.getChildrenNS(self.xsdNSAlias, "simpleType"):
+ try:
+ self.checkSimpleTypeDef (childSimpleType, attrName, attributeValue, returnDict)
+ return
+ except SimpleTypeError, errstr:
+ pass
+
+ raise SimpleTypeError ("%s (%s) is no valid union member type (%s)!" %(attrName, attributeValue, memberTypes))
+
+
+ ########################################
+ # substitute multiple whitespace characters by a single ' '
+ #
+ def _collapseString (self, strValue):
+ return re.sub('\s+', ' ', strValue)
+
+ ########################################
+ # substitute each whitespace characters by a single ' '
+ #
+ def _normalizeString (self, strValue):
+ return re.sub('\s', ' ', strValue)
+
+
+
+
+def validateBaseType (simpleType, attributeValue, returnDict):
+# TODO: Many base types are not completely defined by datatypes.xsd
+ simpleTypeDict = {"xsd:string": _checkStringType,
+ "xsd:hexBinary": _checkHexBinaryType,
+ "xsd:integer": _checkIntegerType,
+ "xsd:boolean": _checkBooleanType,
+ "xsd:QName": _checkQNameType,
+ }
+
+ simpleType = string.replace(simpleType, "xs:", "xsd:")
+ if simpleTypeDict.has_key (simpleType):
+ simpleTypeDict[simpleType] (simpleType, attributeValue, returnDict)
+
+ elif simpleType != "xsd:anySimpleType":
+ if simpleType in ("xsd:decimal", "xsd:float", "xsd:double", "xsd:base64Binary", "xsd:anyURI", "xsd:NOTATION",
+ "xsd:duration", "xsd:dateTime", "xsd:time", "xsd:date",
+ "xsd:gYearMonth", "xsd:gMonthDay", "xsd:gYear", "xsd:gMonth", "xsd:gDay"):
+ print "INFO: Check of simple type '%s' currently not supported!" %(simpleType)
+ else:
+ # TODO: Fehler im XSD-File => Check muss an anderer Stelle erfolgen
+ raise BaseTypeError("uses unknown type '%s'!" %(simpleType))
+
+
+def _checkStringType (simpleType, attributeValue, returnDict):
+ # all valid??
+ returnDict["length"] = len(attributeValue)
+
+def _checkHexBinaryType (simpleType, attributeValue, returnDict):
+ _checkIntegerRange (attributeValue, 16, 0, sys.maxint, returnDict)
+ returnDict["length"] = len(attributeValue)
+
+def _checkIntegerType (simpleType, attributeValue, returnDict):
+ _checkIntegerRange (attributeValue, 10, -sys.maxint-1, sys.maxint, returnDict)
+
+def _checkBooleanType (simpleType, attributeValue, returnDict):
+ if attributeValue not in ("true", "false", "1", "0"):
+ raise BaseTypeError("is not a boolean value!")
+
+def _checkQNameType (simpleType, attributeValue, returnDict):
+ # TODO: fill
+ returnDict["length"] = len(attributeValue)
+
+def _checkIntegerRange (attributeValue, base, minBase, maxBase, returnDict):
+ try:
+ value = string.atoi (attributeValue, base=base)
+ except:
+ if base == 16:
+ raise BaseTypeError("is not a hexadecimal value!")
+ else:
+ raise BaseTypeError("is not an integer!")
+
+ if value < minBase or value > maxBase:
+ raise BaseTypeError("is out of range (%d..%d)!" %(minBase, maxBase))
+
+ returnDict["orderedValue"] = value
+
+
+
+########################################
+# define own exception for XML schema validation errors
+#
+class SimpleTypeError (StandardError):
+ pass
+
+class BaseTypeError (StandardError):
+ pass