minixsv/xsvalSimpleTypes.py
changeset 0 b622defdfd98
equal deleted inserted replaced
-1:000000000000 0:b622defdfd98
       
     1 #
       
     2 # # minixsv, Release 0.3
       
     3 # file: xsvalSimpleTypes.py
       
     4 #
       
     5 # class for validation of XML schema simple types
       
     6 #
       
     7 # history:
       
     8 # 2004-09-09 rl   created
       
     9 #
       
    10 # Copyright (c) 2004 by Roland Leuthe.  All rights reserved.
       
    11 #
       
    12 # --------------------------------------------------------------------
       
    13 # The minixsv XML schema validator is
       
    14 #
       
    15 # Copyright (c) 2004 by Roland Leuthe
       
    16 #
       
    17 # By obtaining, using, and/or copying this software and/or its
       
    18 # associated documentation, you agree that you have read, understood,
       
    19 # and will comply with the following terms and conditions:
       
    20 #
       
    21 # Permission to use, copy, modify, and distribute this software and
       
    22 # its associated documentation for any purpose and without fee is
       
    23 # hereby granted, provided that the above copyright notice appears in
       
    24 # all copies, and that both that copyright notice and this permission
       
    25 # notice appear in supporting documentation, and that the name of
       
    26 # the author not be used in advertising or publicity
       
    27 # pertaining to distribution of the software without specific, written
       
    28 # prior permission.
       
    29 #
       
    30 # THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
       
    31 # TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
       
    32 # ABILITY AND FITNESS.  IN NO EVENT SHALL THE AUTHOR
       
    33 # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
       
    34 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
       
    35 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
       
    36 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
       
    37 # OF THIS SOFTWARE.
       
    38 # --------------------------------------------------------------------
       
    39 
       
    40 
       
    41 import sys
       
    42 import string
       
    43 import re
       
    44 
       
    45 
       
    46 class XsSimpleTypeVal:
       
    47 
       
    48     def __init__ (self, parent):
       
    49         self.parent = parent
       
    50         self.xmlIf  = parent.xmlIf
       
    51         self.xsdNSAlias = parent.xsdNSAlias
       
    52         self.xsdTree    = parent.xsdTree
       
    53         
       
    54         
       
    55     ########################################
       
    56     # validate given value against simpleType
       
    57     #
       
    58     def checkSimpleType (self, attrName, typeName, attributeValue, returnDict):
       
    59         localTypeName = self.xmlIf.extractLocalName(typeName)
       
    60         if self.parent.xsdTypeDict.has_key(localTypeName):
       
    61             typedefNode = self.parent.xsdTypeDict[localTypeName]
       
    62             if typedefNode.getTagName () == self.xsdNSAlias + "simpleType":
       
    63                 self.checkSimpleTypeDef (typedefNode, attrName, attributeValue, returnDict)
       
    64             else:
       
    65                 raise SimpleTypeError("Type '%s' must be simple type!" %(typeName))
       
    66         else:
       
    67             try:
       
    68                 validateBaseType (typeName, attributeValue, returnDict)
       
    69             except BaseTypeError, errstr:
       
    70                 raise SimpleTypeError("Value of '%s' (%s) %s" %(attrName, attributeValue, errstr))
       
    71         
       
    72 
       
    73     ########################################
       
    74     # validate given value against simpleType node
       
    75     #
       
    76     def checkSimpleTypeDef (self, xsdElement, attrName, attributeValue, returnDict):
       
    77         restrictionElement = xsdElement.getFirstChildNS(self.xsdNSAlias, "restriction")
       
    78         listElement        = xsdElement.getFirstChildNS(self.xsdNSAlias, "list")
       
    79         unionElement       = xsdElement.getFirstChildNS(self.xsdNSAlias, "union")
       
    80         if restrictionElement != None:
       
    81             self._checkRestrictionTag (restrictionElement, attrName, attributeValue, returnDict)
       
    82         elif listElement != None:
       
    83             self._checkListTag (listElement, attrName, attributeValue, returnDict)
       
    84         elif unionElement != None:
       
    85             self._checkUnionTag (unionElement, attrName, attributeValue, returnDict)
       
    86         
       
    87     ########################################
       
    88     # validate given value against restriction node
       
    89     #
       
    90     def _checkRestrictionTag (self, xsdElement, attrName, attributeValue, returnDict):
       
    91         # first check against base type
       
    92         baseType = xsdElement.getAttribute("base")
       
    93         if baseType != None:
       
    94             self.checkSimpleType (attrName, baseType, attributeValue, returnDict)
       
    95         else:
       
    96             baseTypeNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "simpleType")
       
    97             self.checkSimpleTypeDef (baseTypeNode, attrName, attributeValue, returnDict)
       
    98 
       
    99         minExcl = xsdElement.getFirstChildNS(self.xsdNSAlias, "minExclusive")
       
   100         minIncl = xsdElement.getFirstChildNS(self.xsdNSAlias, "minInclusive")
       
   101         maxExcl = xsdElement.getFirstChildNS(self.xsdNSAlias, "maxExclusive")
       
   102         maxIncl = xsdElement.getFirstChildNS(self.xsdNSAlias, "maxInclusive")
       
   103 
       
   104         if minExcl != None:
       
   105             minExclReturnDict = {}
       
   106             minExclValue = minExcl.getAttribute("value")
       
   107             self.checkSimpleType (attrName, baseType, minExclValue, minExclReturnDict)
       
   108             if returnDict.has_key("orderedValue") and minExclReturnDict.has_key("orderedValue"):
       
   109                 if returnDict["orderedValue"] <= minExclReturnDict["orderedValue"]:
       
   110                     raise SimpleTypeError ("Value of %s (%s) is <= minExclusive (%s)" %(attrName, attributeValue, minExclValue))
       
   111         elif minIncl != None:
       
   112             minInclReturnDict = {}
       
   113             minInclValue = minIncl.getAttribute("value")
       
   114             self.checkSimpleType (attrName, baseType, minInclValue, minInclReturnDict)
       
   115             if returnDict.has_key("orderedValue") and minInclReturnDict.has_key("orderedValue"):
       
   116                 if returnDict["orderedValue"] < minInclReturnDict["orderedValue"]:
       
   117                     raise SimpleTypeError ("Value of %s (%s) is < minInclusive (%s)" %(attrName, attributeValue, minInclValue))
       
   118         if maxExcl != None:
       
   119             maxExclReturnDict = {}
       
   120             maxExclValue = maxExcl.getAttribute("value")
       
   121             self.checkSimpleType (attrName, baseType, maxExclValue, maxExclReturnDict)
       
   122             if returnDict.has_key("orderedValue") and maxExclReturnDict.has_key("orderedValue"):
       
   123                 if returnDict["orderedValue"] >= maxExclReturnDict["orderedValue"]:
       
   124                     raise SimpleTypeError ("Value of %s (%s) is >= maxExclusive (%s)" %(attrName, attributeValue, maxExclValue))
       
   125         elif maxIncl != None:
       
   126             maxInclReturnDict = {}
       
   127             maxInclValue = maxIncl.getAttribute("value")
       
   128             self.checkSimpleType (attrName, baseType, maxInclValue, maxInclReturnDict)
       
   129             if returnDict.has_key("orderedValue") and maxInclReturnDict.has_key("orderedValue"):
       
   130                 if returnDict["orderedValue"] > maxInclReturnDict["orderedValue"]:
       
   131                     raise SimpleTypeError ("Value of %s (%s) is > maxInclusive (%s)" %(attrName, attributeValue, maxInclValue))
       
   132 
       
   133         totalDigitsNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "totalDigits")
       
   134         if totalDigitsNode != None:
       
   135             totalDigitsValue = totalDigitsNode.getAttribute("value")
       
   136             if totalDigitsNode.getAttribute("fixed") == "true":
       
   137                 if len(re.findall("\d" ,attributeValue)) != string.atoi(totalDigitsValue):
       
   138                     raise SimpleTypeError ("Total number of digits != %s for %s (%s)" %(totalDigitsValue, attrName, attributeValue))
       
   139             else:
       
   140                 if len(re.findall("\d" ,attributeValue)) > string.atoi(totalDigitsValue):
       
   141                     raise SimpleTypeError ("Total number of digits > %s for %s (%s)" %(totalDigitsValue, attrName, attributeValue))
       
   142         fractionDigitsNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "fractionDigits")
       
   143         if fractionDigitsNode != None:
       
   144             fractionDigitsValue = fractionDigitsNode.getAttribute("value")
       
   145             result = re.search("(?P<intDigits>\d+)(?P<dot>\.)(?P<fracDigits>\d+)" ,attributeValue)
       
   146             if result != None:
       
   147                 numberOfFracDigits = len (result.group('fracDigits'))
       
   148             else:
       
   149                 numberOfFracDigits = 0
       
   150             if fractionDigitsNode.getAttribute("fixed") == "true" and numberOfFracDigits != string.atoi(fractionDigitsValue):
       
   151                 raise SimpleTypeError ("Fraction number of digits != %s for %s (%s)" %(fractionDigitsValue, attrName, attributeValue))
       
   152             elif numberOfFracDigits > string.atoi(fractionDigitsValue):
       
   153                 raise SimpleTypeError ("Fraction number of digits > %s for %s (%s)" %(fractionDigitsValue, attrName, attributeValue))
       
   154 
       
   155         if returnDict.has_key("length"):            
       
   156             lengthNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "length")
       
   157             if lengthNode != None:
       
   158                 length = string.atoi(lengthNode.getAttribute("value"))
       
   159                 if returnDict["length"] != length:
       
   160                     raise SimpleTypeError ("Length of %s (%s) must be %d!" %(attrName, attributeValue, length))
       
   161             minLengthNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "minLength")
       
   162             if minLengthNode != None:
       
   163                 minLength = string.atoi(minLengthNode.getAttribute("value"))
       
   164                 if returnDict["length"] < minLength:
       
   165                     raise SimpleTypeError ("Length of %s (%s) must be >= %d!" %(attrName, attributeValue, minLength))
       
   166             maxLengthNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "maxLength")
       
   167             if maxLengthNode != None:
       
   168                 maxLength = string.atoi(maxLengthNode.getAttribute("value"))
       
   169                 if returnDict["length"] > maxLength:
       
   170                     raise SimpleTypeError ("Length of %s (%s) must be <= %d!" %(attrName, attributeValue, maxLength))
       
   171         
       
   172         enumerationElementList = xsdElement.getChildrenNS(self.xsdNSAlias, "enumeration")
       
   173         if enumerationElementList != []:
       
   174             for enumeration in enumerationElementList:
       
   175                 if enumeration.getAttribute ("value") == attributeValue:
       
   176                     break
       
   177             else:
       
   178                 raise SimpleTypeError ("Enumeration value '%s' not allowed!" %(attributeValue))
       
   179             
       
   180         patternNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "pattern")
       
   181         if patternNode != None:
       
   182             rePattern = patternNode.getAttribute("value")
       
   183             regexObj = re.match(rePattern, attributeValue)
       
   184             if not regexObj or regexObj.end() != len(attributeValue):
       
   185                 raise SimpleTypeError ("Attribute value '%s' does not match pattern '%s'!" %(attributeValue, rePattern))                        
       
   186 
       
   187         whiteSpace = xsdElement.getFirstChildNS(self.xsdNSAlias, "whiteSpace")
       
   188         if whiteSpace != None:
       
   189             wsAction = whiteSpace.getAttribute("value")
       
   190             if wsAction == "replace":
       
   191                 normalizedValue = self._normalizeString(attributeValue)
       
   192                 if normalizedValue != attributeValue:
       
   193                     returnDict["adaptedAttrValue"] = normalizedValue
       
   194             elif wsAction == "collapse":
       
   195                 collapsedValue = self._collapseString(attributeValue)
       
   196                 if collapsedValue != attributeValue:
       
   197                     returnDict["adaptedAttrValue"] = collapsedValue
       
   198                 
       
   199 
       
   200     ########################################
       
   201     # validate given value against list node
       
   202     #
       
   203     def _checkListTag (self, xsdElement, attrName, attributeValue, returnDict):
       
   204         if attributeValue != "":
       
   205             itemType = xsdElement.getAttribute ("itemType")
       
   206             # substitute multiple whitespace characters by a single ' '
       
   207             collapsedValue = self._collapseString(attributeValue)
       
   208             if collapsedValue != attributeValue:
       
   209                 returnDict["adaptedAttrValue"] = collapsedValue
       
   210 
       
   211             # divide up attributeValue => store it into list
       
   212             attributeList = string.split(collapsedValue, " ")
       
   213             for attrValue in attributeList:
       
   214                 elementReturnDict = {}
       
   215                 if itemType != None:
       
   216                     self.checkSimpleType (attrName, itemType, attrValue, elementReturnDict)
       
   217                 else:
       
   218                     itemTypeNode = xsdElement.getFirstChildNS(self.xsdNSAlias, "simpleType")
       
   219                     self.checkSimpleTypeDef (itemTypeNode, attrName, attrValue, elementReturnDict)
       
   220     
       
   221             returnDict["length"] = len(attributeList)
       
   222         else:
       
   223             returnDict["length"] = 0
       
   224 
       
   225 
       
   226     ########################################
       
   227     # validate given value against union node
       
   228     #
       
   229     def _checkUnionTag (self, xsdElement, attrName, attributeValue, returnDict):
       
   230         memberTypes = xsdElement.getAttribute ("memberTypes")
       
   231         if memberTypes != None:
       
   232             # substitute multiple whitespace characters by a single ' '
       
   233             # divide up attributeValue => store it into list
       
   234             for memberType in string.split(self._collapseString(memberTypes), " "):
       
   235                 try:
       
   236                     self.checkSimpleType (attrName, memberType, attributeValue, returnDict)
       
   237                     return
       
   238                 except SimpleTypeError, errstr:
       
   239                     pass
       
   240                     
       
   241         # memberTypes and additional type definitions is legal!
       
   242         for childSimpleType in xsdElement.getChildrenNS(self.xsdNSAlias, "simpleType"):
       
   243             try:
       
   244                 self.checkSimpleTypeDef (childSimpleType, attrName, attributeValue, returnDict)
       
   245                 return
       
   246             except SimpleTypeError, errstr:
       
   247                 pass
       
   248         
       
   249         raise SimpleTypeError ("%s (%s) is no valid union member type (%s)!" %(attrName, attributeValue, memberTypes))
       
   250 
       
   251         
       
   252     ########################################
       
   253     # substitute multiple whitespace characters by a single ' '
       
   254     #
       
   255     def _collapseString (self, strValue):
       
   256         return re.sub('\s+', ' ', strValue)
       
   257 
       
   258     ########################################
       
   259     # substitute each whitespace characters by a single ' '
       
   260     #
       
   261     def _normalizeString (self, strValue):
       
   262         return re.sub('\s', ' ', strValue)
       
   263 
       
   264 
       
   265 
       
   266 
       
   267 def validateBaseType (simpleType, attributeValue, returnDict):
       
   268 # TODO: Many base types are not completely defined by datatypes.xsd
       
   269     simpleTypeDict = {"xsd:string":           _checkStringType,
       
   270                       "xsd:hexBinary":        _checkHexBinaryType,
       
   271                       "xsd:integer":          _checkIntegerType,
       
   272                       "xsd:boolean":          _checkBooleanType,
       
   273                       "xsd:QName":            _checkQNameType,
       
   274                       }
       
   275 
       
   276     simpleType = string.replace(simpleType, "xs:", "xsd:")
       
   277     if simpleTypeDict.has_key (simpleType):
       
   278         simpleTypeDict[simpleType] (simpleType, attributeValue, returnDict)
       
   279 
       
   280     elif simpleType != "xsd:anySimpleType":
       
   281         if simpleType in ("xsd:decimal", "xsd:float", "xsd:double", "xsd:base64Binary", "xsd:anyURI", "xsd:NOTATION",
       
   282                             "xsd:duration", "xsd:dateTime", "xsd:time", "xsd:date", 
       
   283                             "xsd:gYearMonth", "xsd:gMonthDay", "xsd:gYear", "xsd:gMonth", "xsd:gDay"):
       
   284             print "INFO: Check of simple type '%s' currently not supported!" %(simpleType)
       
   285         else:
       
   286             # TODO: Fehler im XSD-File => Check muss an anderer Stelle erfolgen
       
   287             raise BaseTypeError("uses unknown type '%s'!" %(simpleType))
       
   288 
       
   289 
       
   290 def _checkStringType (simpleType, attributeValue, returnDict):
       
   291     # all valid??
       
   292     returnDict["length"] = len(attributeValue)
       
   293 
       
   294 def _checkHexBinaryType (simpleType, attributeValue, returnDict):   
       
   295     _checkIntegerRange (attributeValue, 16, 0, sys.maxint, returnDict)
       
   296     returnDict["length"] = len(attributeValue)
       
   297     
       
   298 def _checkIntegerType (simpleType, attributeValue, returnDict):
       
   299     _checkIntegerRange (attributeValue, 10, -sys.maxint-1, sys.maxint, returnDict)
       
   300 
       
   301 def _checkBooleanType (simpleType, attributeValue, returnDict):
       
   302     if attributeValue not in ("true", "false", "1", "0"):
       
   303         raise BaseTypeError("is not a boolean value!")
       
   304         
       
   305 def _checkQNameType (simpleType, attributeValue, returnDict):
       
   306     # TODO: fill
       
   307     returnDict["length"] = len(attributeValue)
       
   308 
       
   309 def _checkIntegerRange (attributeValue, base, minBase, maxBase, returnDict):
       
   310     try:
       
   311         value = string.atoi (attributeValue, base=base)
       
   312     except:
       
   313         if base == 16:
       
   314             raise BaseTypeError("is not a hexadecimal value!")
       
   315         else:
       
   316             raise BaseTypeError("is not an integer!")
       
   317     
       
   318     if value < minBase or value > maxBase:
       
   319         raise BaseTypeError("is out of range (%d..%d)!" %(minBase, maxBase))
       
   320     
       
   321     returnDict["orderedValue"] = value
       
   322     
       
   323 
       
   324 
       
   325 ########################################
       
   326 # define own exception for XML schema validation errors
       
   327 #
       
   328 class SimpleTypeError (StandardError):
       
   329     pass
       
   330     
       
   331 class BaseTypeError (StandardError):
       
   332     pass