etisserant@0: # etisserant@0: # minixsv, Release 0.3 etisserant@0: # file: xsvalBase.py etisserant@0: # etisserant@0: # XML schema validator base class etisserant@0: # etisserant@0: # history: etisserant@0: # 2004-10-07 rl created etisserant@0: # etisserant@0: # Copyright (c) 2004 by Roland Leuthe. All rights reserved. etisserant@0: # etisserant@0: # -------------------------------------------------------------------- etisserant@0: # The minixsv XML schema validator is etisserant@0: # etisserant@0: # Copyright (c) 2004 by Roland Leuthe etisserant@0: # etisserant@0: # By obtaining, using, and/or copying this software and/or its etisserant@0: # associated documentation, you agree that you have read, understood, etisserant@0: # and will comply with the following terms and conditions: etisserant@0: # etisserant@0: # Permission to use, copy, modify, and distribute this software and etisserant@0: # its associated documentation for any purpose and without fee is etisserant@0: # hereby granted, provided that the above copyright notice appears in etisserant@0: # all copies, and that both that copyright notice and this permission etisserant@0: # notice appear in supporting documentation, and that the name of etisserant@0: # the author not be used in advertising or publicity etisserant@0: # pertaining to distribution of the software without specific, written etisserant@0: # prior permission. etisserant@0: # etisserant@0: # THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD etisserant@0: # TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- etisserant@0: # ABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR etisserant@0: # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY etisserant@0: # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, etisserant@0: # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS etisserant@0: # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE etisserant@0: # OF THIS SOFTWARE. etisserant@0: # -------------------------------------------------------------------- etisserant@0: etisserant@0: from xsvalErrorHandler import * etisserant@0: import xsvalSimpleTypes etisserant@0: etisserant@0: ########################################################### etisserant@0: # Validator class for validating one input file against one XML schema file etisserant@0: etisserant@0: class XsValBase: etisserant@0: etisserant@0: def __init__(self, xmlIf, errorHandler): etisserant@0: self.xmlIf = xmlIf etisserant@0: self.errorHandler = errorHandler etisserant@0: etisserant@0: self._raiseError = self.errorHandler.raiseError etisserant@0: self._addError = self.errorHandler.addError etisserant@0: self._addWarning = self.errorHandler.addWarning etisserant@0: etisserant@0: self.checkKeyrefList = [] etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # validate inputTree against xsdTree etisserant@0: # etisserant@0: def validate (self, inputTree, xsdTree): etisserant@0: self.inputTree = inputTree etisserant@0: self.xsdTree = xsdTree etisserant@0: etisserant@0: self.xsdRoot = self.xsdTree.getRootNode() etisserant@0: self.xsdNSAlias = self.xmlIf.extractNamespaceAlias(self.xsdRoot.getTagName()) etisserant@0: self.inputRoot = self.inputTree.getRootNode() etisserant@0: self.inputNSAlias = self.xmlIf.extractNamespaceAlias(self.inputRoot.getTagName()) etisserant@0: etisserant@0: self.simpleTypeVal = xsvalSimpleTypes.XsSimpleTypeVal(self) etisserant@0: etisserant@0: self._setupLookupTables() etisserant@0: etisserant@0: inputRootTagName = self.inputRoot.getTagName() etisserant@0: inputRootLocalName = self.inputRoot.getLocalName() etisserant@0: if self.xsdElementDict.has_key(inputRootLocalName): etisserant@0: # start recursive schema validation etisserant@0: try: etisserant@0: self._checkElementTag (self.xsdElementDict[inputRootLocalName], inputRootTagName, (self.inputRoot,), 0) etisserant@0: except TagException, errInst: etisserant@0: self._addError (errInst.errstr, errInst.node, errInst.endTag) etisserant@0: etisserant@0: # validate keyrefs etisserant@0: for inputElement, keyrefNode in self.checkKeyrefList: etisserant@0: self._checkKeyRefConstraint (keyrefNode, inputElement) etisserant@0: else: etisserant@0: self._raiseError ("Used root tag %s not found in schema file!" %(inputRootTagName), self.inputRoot) etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # setup lookup dictionaries used during validation etisserant@0: # etisserant@0: def _setupLookupTables (self): etisserant@0: # retrieve all elements etisserant@0: self.xsdElementDict = {} etisserant@0: for xsdTypeNode in self.xsdRoot.getChildrenNS(self.xsdNSAlias, "element"): etisserant@0: self.xsdElementDict[xsdTypeNode.getAttribute("name")] = xsdTypeNode etisserant@0: etisserant@0: # retrieve all type definitions (complex and simple types) etisserant@0: self.xsdTypeDict = {} etisserant@0: for xsdTypeNode in self.xsdRoot.getChildrenNS(self.xsdNSAlias, "complexType"): etisserant@0: self.xsdTypeDict[xsdTypeNode.getAttribute("name")] = xsdTypeNode etisserant@0: etisserant@0: for xsdTypeNode in self.xsdRoot.getChildrenNS(self.xsdNSAlias, "simpleType"): etisserant@0: self.xsdTypeDict[xsdTypeNode.getAttribute("name")] = xsdTypeNode etisserant@0: etisserant@0: # retrieve all group definitions etisserant@0: self.xsdGroupDict = {} etisserant@0: for xsdTypeNode in self.xsdRoot.getChildrenNS(self.xsdNSAlias, "group"): etisserant@0: self.xsdGroupDict[xsdTypeNode.getAttribute("name")] = xsdTypeNode etisserant@0: etisserant@0: # retrieve all attribute group definitions etisserant@0: self.xsdAttributeGroupDict = {} etisserant@0: for xsdTypeNode in self.xsdRoot.getChildrenNS(self.xsdNSAlias, "attributeGroup"): etisserant@0: self.xsdAttributeGroupDict[xsdTypeNode.getAttribute("name")] = xsdTypeNode etisserant@0: etisserant@0: # retrieve all identity constraints etisserant@0: self.xsdIdentityConstrDict = {} etisserant@0: for identConstrTagName in ("unique", "key", "keyref"): etisserant@0: identConstrNodeList = self.xsdRoot.getElementsByTagNameNS (self.xsdNSAlias, identConstrTagName) etisserant@0: for identConstrNode in identConstrNodeList: etisserant@0: identConstrName = identConstrNode.getAttribute("name") etisserant@0: if not self.xsdIdentityConstrDict.has_key(identConstrName): etisserant@0: self.xsdIdentityConstrDict[identConstrName] = {"Node": identConstrNode, "ValueDict":{}} etisserant@0: else: etisserant@0: self._raiseError ("Duplicate identity constraint name '%s' found in schema definition!" %(identConstrName), identConstrNode) etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # validate inputElement against complexType node etisserant@0: # etisserant@0: def _checkComplexTypeTag (self, xsdParentElementNode, xsdElement, inputElement, inputElementChildIndex, usedAsBaseType=None): etisserant@0: baseTypeAttributes = {"__SPECIAL_ATTRS__":{}} etisserant@0: if xsdParentElementNode.getAttribute ("nillable") == "true": etisserant@0: baseTypeAttributes["__SPECIAL_ATTRS__"]["nil"] = "xsd:boolean" etisserant@0: etisserant@0: complexContentElement = xsdElement.getFirstChildNS(self.xsdNSAlias, "complexContent") etisserant@0: if complexContentElement != None: etisserant@0: inputElementChildIndex, baseTypeAttributes = self._checkComplexContentTag (xsdParentElementNode, complexContentElement, inputElement, inputElementChildIndex, usedAsBaseType, baseTypeAttributes) etisserant@0: else: etisserant@0: inputElementChildIndex, baseTypeAttributes = self._checkComplexTypeContent (xsdElement, inputElement, inputElementChildIndex, usedAsBaseType, baseTypeAttributes) etisserant@0: return inputElementChildIndex, baseTypeAttributes etisserant@0: etisserant@0: def _checkComplexContentTag (self, xsdParentElementNode, xsdElement, inputElement, inputElementChildIndex, usedAsBaseType, baseTypeAttributes): etisserant@0: extensionElement = xsdElement.getFirstChildNS(self.xsdNSAlias, "extension") etisserant@0: if extensionElement != None: etisserant@0: inputElementChildIndex, baseTypeAttributes = self._checkExtensionComplexContent (xsdParentElementNode, extensionElement, inputElement, inputElementChildIndex, usedAsBaseType, baseTypeAttributes) etisserant@0: else: etisserant@0: restrictionElement = xsdElement.getFirstChildNS(self.xsdNSAlias, "restriction") etisserant@0: if restrictionElement != None: etisserant@0: inputElementChildIndex, baseTypeAttributes = self._checkRestrictionComplexContent (xsdParentElementNode, restrictionElement, inputElement, inputElementChildIndex, usedAsBaseType, baseTypeAttributes) etisserant@0: return inputElementChildIndex, baseTypeAttributes etisserant@0: etisserant@0: def _checkExtensionComplexContent (self, xsdParentElementNode, xsdElement, inputElement, inputElementChildIndex, usedAsBaseType, baseTypeAttributes): etisserant@0: baseType = self.xmlIf.extractLocalName(xsdElement.getAttribute("base")) etisserant@0: inputElementChildIndex, baseTypeAttributes = self._checkComplexTypeTag (xsdParentElementNode, self.xsdTypeDict[baseType], inputElement, inputElementChildIndex, "extension") etisserant@0: etisserant@0: inputElementChildIndex, baseTypeAttributes = self._checkComplexTypeContent (xsdElement, inputElement, inputElementChildIndex, usedAsBaseType, baseTypeAttributes) etisserant@0: return inputElementChildIndex, baseTypeAttributes etisserant@0: etisserant@0: def _checkRestrictionComplexContent (self, xsdParentElementNode, xsdElement, inputElement, inputElementChildIndex, usedAsBaseType, baseTypeAttributes): etisserant@0: # first check against base type (retrieve only the base type attributes) etisserant@0: baseType = self.xmlIf.extractLocalName(xsdElement.getAttribute("base")) etisserant@0: inputElementChildIndex, baseTypeAttributes = self._checkComplexTypeTag (xsdParentElementNode, self.xsdTypeDict[baseType], inputElement, inputElementChildIndex, "restriction") etisserant@0: etisserant@0: # then check input against derived complex type etisserant@0: inputElementChildIndex, baseTypeAttributes = self._checkComplexTypeContent (xsdElement, inputElement, inputElementChildIndex, usedAsBaseType, baseTypeAttributes) etisserant@0: return inputElementChildIndex, baseTypeAttributes etisserant@0: etisserant@0: def _checkComplexTypeContent (self, xsdElement, inputElement, inputElementChildIndex, usedAsBaseType, baseTypeAttributes): etisserant@0: inputTagName = inputElement.getTagName() etisserant@0: childTags = inputElement.getChildren() etisserant@0: if usedAsBaseType in (None, "extension"): etisserant@0: validChildTags = xsdElement.getChildren() etisserant@0: for validChildTag in validChildTags: etisserant@0: if validChildTag.getLocalName() not in ("attribute", "attributeGroup", "anyAttribute"): etisserant@0: inputElementChildIndex = self._checkParticle (validChildTag, inputElement, childTags, inputElementChildIndex) etisserant@0: etisserant@0: if usedAsBaseType == None and inputElementChildIndex < len (childTags): etisserant@0: self._addError ("Unexpected child tag '%s' in tag '%s' found!" %(childTags[inputElementChildIndex].getTagName(), inputTagName), childTags[inputElementChildIndex]) etisserant@0: etisserant@0: if usedAsBaseType in (None,): etisserant@0: self._checkAttributeTags (xsdElement, inputElement, baseTypeAttributes) etisserant@0: etisserant@0: if usedAsBaseType in ("restriction", "extension"): etisserant@0: validAttributes = xsdElement.getChildrenNS(self.xsdNSAlias, "attribute") etisserant@0: for validAttrGroup in xsdElement.getChildrenNS(self.xsdNSAlias, "attributeGroup"): etisserant@0: attributeGroupRef = self.xmlIf.extractLocalName(validAttrGroup.getAttribute("ref")) etisserant@0: validAttributes.extend (self.xsdAttributeGroupDict[attributeGroupRef].getChildrenNS(self.xsdNSAlias, "attribute")) etisserant@0: for validAttribute in validAttributes: etisserant@0: baseTypeAttributes[validAttribute.getAttribute("name")] = validAttribute etisserant@0: return inputElementChildIndex, baseTypeAttributes etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # validate inputNodeList against xsdNode etisserant@0: # etisserant@0: def _checkList (self, elementMethod, xsdNode, inputParentNode, inputNodeList, currIndex): etisserant@0: if not xsdNode.hasAttribute("minOccurs"): etisserant@0: xsdNode.setAttribute("minOccurs", "1") # default etisserant@0: if not xsdNode.hasAttribute("maxOccurs"): etisserant@0: xsdNode.setAttribute("maxOccurs", "1") # default etisserant@0: etisserant@0: minOccurs = string.atoi(xsdNode.getAttribute("minOccurs")) etisserant@0: maxOccurs = -1 etisserant@0: if xsdNode.getAttribute("maxOccurs") != "unbounded": etisserant@0: maxOccurs = string.atoi(xsdNode.getAttribute("maxOccurs")) etisserant@0: occurs = 0 etisserant@0: while maxOccurs == -1 or occurs < maxOccurs: etisserant@0: try: etisserant@0: newIndex = elementMethod (xsdNode, inputParentNode, inputNodeList, currIndex) etisserant@0: occurs += 1 etisserant@0: if newIndex > currIndex: etisserant@0: currIndex = newIndex etisserant@0: else: etisserant@0: break # no suitable element found etisserant@0: except TagException, errInst: etisserant@0: break etisserant@0: etisserant@0: if occurs == 0 and minOccurs > 0: etisserant@0: raise errInst etisserant@0: elif occurs < minOccurs: etisserant@0: expInputTagName = xsdNode.getAttribute("name") etisserant@0: if expInputTagName == None: etisserant@0: expInputTagName = self.xmlIf.extractLocalName(xsdNode.getAttribute("ref")) etisserant@0: etisserant@0: errInst.errstr = "Minimum number (%d) of child tags '%s' in tag '%s' not available (only %d)!" %(minOccurs, expInputTagName, inputParentNode.getTagName(), occurs) etisserant@0: raise errInst etisserant@0: etisserant@0: return currIndex etisserant@0: etisserant@0: ######################################## etisserant@0: # validate inputNode against element node etisserant@0: # etisserant@0: def _checkElementTag (self, xsdNode, inputParentNode, inputNodeList, currIndex): etisserant@0: if xsdNode.hasAttribute("ref"): etisserant@0: refAttr = self.xmlIf.extractLocalName(xsdNode.getAttribute("ref")) etisserant@0: currIndex = self._checkElementTag (self.xsdElementDict[refAttr], inputParentNode, inputNodeList, currIndex) etisserant@0: etisserant@0: else: etisserant@0: nameAttr = xsdNode.getAttribute ("name") etisserant@0: if currIndex >= len (inputNodeList): etisserant@0: raise TagException ("Missing child tag '%s' in tag '%s'!" %(nameAttr, inputParentNode.getTagName()), inputParentNode, 1) etisserant@0: etisserant@0: inputNode = inputNodeList[currIndex] etisserant@0: if nameAttr != inputNode.getLocalName(): etisserant@0: raise TagException ("Missing child tag '%s' in tag '%s'!" %(nameAttr, inputParentNode.getTagName()), inputNode, 0) etisserant@0: etisserant@0: simpleType = None etisserant@0: complexTypeNode = xsdNode.getFirstChildNS (self.xsdNSAlias, "complexType") etisserant@0: simpleTypeNode = xsdNode.getFirstChildNS (self.xsdNSAlias, "simpleType") etisserant@0: if xsdNode.hasAttribute("type"): etisserant@0: typeAttr = xsdNode.getAttribute ("type") etisserant@0: localTypeAttr = self.xmlIf.extractLocalName(typeAttr) etisserant@0: if self.xsdTypeDict.has_key (localTypeAttr) and self.xsdTypeDict[localTypeAttr].getLocalName() == "complexType": etisserant@0: complexTypeNode = self.xsdTypeDict[localTypeAttr] etisserant@0: else: etisserant@0: simpleType = typeAttr etisserant@0: etisserant@0: if complexTypeNode != None: etisserant@0: try: etisserant@0: self._checkComplexTypeTag (xsdNode, complexTypeNode, inputNode, 0) etisserant@0: except TagException, errInst: etisserant@0: self._addError (errInst.errstr, errInst.node, errInst.endTag) etisserant@0: else: etisserant@0: try: etisserant@0: simpleTypeReturnDict = {} etisserant@0: if simpleTypeNode != None: etisserant@0: self.simpleTypeVal.checkSimpleTypeDef (simpleTypeNode, inputNode.getTagName(), inputNode.getElementValue(), simpleTypeReturnDict) etisserant@0: elif simpleType != None: etisserant@0: self.simpleTypeVal.checkSimpleType (inputNode.getTagName(), simpleType, inputNode.getElementValue(), simpleTypeReturnDict) etisserant@0: # TODO: What to check if np type is specified for the element? etisserant@0: etisserant@0: if simpleTypeReturnDict.has_key("adaptedAttrValue"): etisserant@0: inputNode.setElementValue(simpleTypeReturnDict["adaptedAttrValue"]) etisserant@0: etisserant@0: except xsvalSimpleTypes.SimpleTypeError, errstr: etisserant@0: self._addError (str(errstr), inputNode) etisserant@0: etisserant@0: currIndex += 1 etisserant@0: etisserant@0: # check unique attributes and keys etisserant@0: childUniqueDefList = xsdNode.getChildrenNS (self.xsdNSAlias, "unique") etisserant@0: for childUniqueDef in childUniqueDefList: etisserant@0: self._checkIdentityConstraint (childUniqueDef, inputNode, "unique") etisserant@0: etisserant@0: childKeyDefList = xsdNode.getChildrenNS (self.xsdNSAlias, "key") etisserant@0: for childKeyDef in childKeyDefList: etisserant@0: self._checkIdentityConstraint (childKeyDef, inputNode, "key") etisserant@0: etisserant@0: childKeyrefDefList = xsdNode.getChildrenNS (self.xsdNSAlias, "keyref") etisserant@0: for childKeyrefDef in childKeyrefDefList: etisserant@0: self.checkKeyrefList.append ((inputNode, childKeyrefDef)) etisserant@0: etisserant@0: return currIndex etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # validate inputNode against sequence node etisserant@0: # etisserant@0: def _checkSequenceTag (self, xsdNode, inputParentNode, inputNodeList, currIndex): etisserant@0: for xsdChildNode in xsdNode.getChildren(): etisserant@0: currIndex = self._checkParticle (xsdChildNode, inputParentNode, inputNodeList, currIndex) etisserant@0: return currIndex etisserant@0: etisserant@0: ######################################## etisserant@0: # validate inputNode against choice node etisserant@0: # etisserant@0: def _checkChoiceTag (self, xsdNode, inputParentNode, inputNodeList, currIndex): etisserant@0: for xsdChildNode in xsdNode.getChildren(): etisserant@0: try: etisserant@0: currIndex = self._checkParticle (xsdChildNode, inputParentNode, inputNodeList, currIndex) etisserant@0: break etisserant@0: except TagException, errInst: etisserant@0: pass etisserant@0: else: etisserant@0: if currIndex < len(inputNodeList): etisserant@0: currNode = inputNodeList[currIndex] etisserant@0: endTag = 0 etisserant@0: else: etisserant@0: currNode = inputParentNode etisserant@0: endTag = 1 etisserant@0: raise TagException ("No suitable child tag for choice found!", currNode, endTag) etisserant@0: etisserant@0: return currIndex etisserant@0: etisserant@0: ######################################## etisserant@0: # validate inputNode against group node etisserant@0: # etisserant@0: def _checkGroupTag (self, xsdNode, inputParentNode, inputNodeList, currIndex): etisserant@0: if xsdNode.hasAttribute("ref"): etisserant@0: refAttr = self.xmlIf.extractLocalName(xsdNode.getAttribute("ref")) etisserant@0: currIndex = self._checkGroupTag (self.xsdGroupDict[refAttr], inputParentNode, inputNodeList, currIndex) etisserant@0: else: etisserant@0: for xsdChildNode in xsdNode.getChildren(): etisserant@0: currIndex = self._checkParticle (xsdChildNode, inputParentNode, inputNodeList, currIndex) etisserant@0: return currIndex etisserant@0: etisserant@0: ######################################## etisserant@0: # validate inputNode against all node etisserant@0: # etisserant@0: def _checkAllTag (self, xsdNode, inputParentNode, inputNodeList, currIndex): etisserant@0: oldIndex = currIndex etisserant@0: xsdChildDict = {} etisserant@0: for xsdChildNode in xsdNode.getChildren(): etisserant@0: xsdChildDict[xsdChildNode] = 0 etisserant@0: while currIndex < len(inputNodeList): etisserant@0: currNode = inputNodeList[currIndex] etisserant@0: for xsdChildNode in xsdChildDict.keys(): etisserant@0: try: etisserant@0: newIndex = self._checkParticle (xsdChildNode, inputParentNode, inputNodeList, currIndex) etisserant@0: except TagException, errInst: etisserant@0: continue etisserant@0: etisserant@0: if xsdChildDict[xsdChildNode] == 0: etisserant@0: xsdChildDict[xsdChildNode] = 1 etisserant@0: currIndex = newIndex etisserant@0: break etisserant@0: else: etisserant@0: raise TagException ("Ambiguous child tag '%s' found in all-group!" %(currNode.getTagName()), currNode) etisserant@0: else: etisserant@0: raise TagException ("Unexpected child tag '%s' for all-group found!" %(currNode.getTagName()), currNode) etisserant@0: etisserant@0: for xsdChildNode, occurs in xsdChildDict.items(): etisserant@0: if xsdChildNode.getAttribute("minOccurs") != "0" and occurs == 0: etisserant@0: raise TagException ("Child tag '%s' missing in all-group (%s)" %(xsdChildNode.getAttribute("name"), inputParentNode.getTagName()), inputNodeList[oldIndex]) etisserant@0: etisserant@0: return currIndex etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # validate inputNode against any node etisserant@0: # etisserant@0: def _checkAnyTag (self, xsdNode, inputParentNode, inputNodeList, currIndex): etisserant@0: processContents = xsdNode.getAttribute("processContents") etisserant@0: if processContents == "skip": etisserant@0: pass etisserant@0: elif processContents == "lax": etisserant@0: # TODO: Was muss hier gecheckt werden? etisserant@0: pass etisserant@0: elif processContents == "strict": etisserant@0: # TODO: Was muss hier gecheckt werden? etisserant@0: pass etisserant@0: etisserant@0: if currIndex < len(inputNodeList): etisserant@0: currIndex = currIndex + 1 etisserant@0: etisserant@0: return currIndex etisserant@0: etisserant@0: ######################################## etisserant@0: # validate inputNode against particle etisserant@0: # etisserant@0: def _checkParticle (self, xsdNode, inputParentNode, inputNodeList, currIndex): etisserant@0: xsdTagName = xsdNode.getTagName() etisserant@0: if xsdTagName == self.xsdNSAlias + "element": etisserant@0: currIndex = self._checkList (self._checkElementTag, xsdNode, inputParentNode, inputNodeList, currIndex) etisserant@0: elif xsdTagName == self.xsdNSAlias + "choice": etisserant@0: currIndex = self._checkList (self._checkChoiceTag, xsdNode, inputParentNode, inputNodeList, currIndex) etisserant@0: elif xsdTagName == self.xsdNSAlias + "sequence": etisserant@0: currIndex = self._checkList (self._checkSequenceTag, xsdNode, inputParentNode, inputNodeList, currIndex) etisserant@0: elif xsdTagName == self.xsdNSAlias + "group": etisserant@0: currIndex = self._checkList (self._checkGroupTag, xsdNode, inputParentNode, inputNodeList, currIndex) etisserant@0: elif xsdTagName == self.xsdNSAlias + "all": etisserant@0: currIndex = self._checkList (self._checkAllTag, xsdNode, inputParentNode, inputNodeList, currIndex) etisserant@0: elif xsdTagName == self.xsdNSAlias + "any": etisserant@0: currIndex = self._checkList (self._checkAnyTag, xsdNode, inputParentNode, inputNodeList, currIndex) etisserant@0: elif xsdTagName == self.xsdNSAlias + "annotation": etisserant@0: pass # nothing to check etisserant@0: else: etisserant@0: self._addError ("Internal error: Invalid tag %s found!" %(xsdTagName)) etisserant@0: return currIndex etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # validate attributes of inputNode against complexType node etisserant@0: # etisserant@0: def _checkAttributeTags (self, xsdNode, inputNode, validAttrDict): etisserant@0: validAttributes = xsdNode.getChildrenNS(self.xsdNSAlias, "attribute") etisserant@0: for validAttrGroup in xsdNode.getChildrenNS(self.xsdNSAlias, "attributeGroup"): etisserant@0: attributeGroupRef = self.xmlIf.extractLocalName(validAttrGroup.getAttribute("ref")) etisserant@0: validAttributes.extend (self.xsdAttributeGroupDict[attributeGroupRef].getChildrenNS(self.xsdNSAlias, "attribute")) etisserant@0: for validAttribute in validAttributes: etisserant@0: if validAttribute.hasAttribute("name"): etisserant@0: keyAttr = validAttribute.getAttribute("name") etisserant@0: else: etisserant@0: keyAttr = self.xmlIf.extractLocalName(validAttribute.getAttribute("ref")) etisserant@0: validAttrDict[keyAttr] = validAttribute etisserant@0: etisserant@0: inputAttrDict = {} etisserant@0: for iAttrName, iAttrValue in inputNode.getAttributeDict().items(): etisserant@0: if self.xmlIf.extractNamespaceAlias (iAttrName) != "xmlns:" and iAttrName != "xmlns": etisserant@0: inputAttrDict[self.xmlIf.extractLocalName(iAttrName)] = iAttrValue etisserant@0: etisserant@0: for attrKey, validAttribute in validAttrDict.items(): etisserant@0: # handle special attributes, e.g. xsi:nil etisserant@0: if attrKey == "__SPECIAL_ATTRS__": etisserant@0: for specialAttrName, specialAttrType in validAttribute.items(): etisserant@0: if inputAttrDict.has_key(specialAttrName): etisserant@0: simpleTypeReturnDict = {} etisserant@0: try: etisserant@0: self.simpleTypeVal.checkSimpleType (specialAttrName, specialAttrType, inputAttrDict[specialAttrName], simpleTypeReturnDict) etisserant@0: except xsvalSimpleTypes.SimpleTypeError, errstr: etisserant@0: self._addError (str(errstr), inputNode) etisserant@0: etisserant@0: del inputAttrDict[specialAttrName] etisserant@0: continue etisserant@0: etisserant@0: attrDict = validAttribute.getAttributeDict() etisserant@0: if attrDict.has_key("ref"): etisserant@0: # TODO: What to do here?? etisserant@0: attrRef = self.xmlIf.extractLocalName(attrDict["ref"]) etisserant@0: if inputAttrDict.has_key(attrRef): etisserant@0: del inputAttrDict[attrRef] etisserant@0: else: etisserant@0: attrName = attrDict["name"] etisserant@0: if not attrDict.has_key("use"): etisserant@0: attrDict["use"] = "optional" etisserant@0: etisserant@0: if inputAttrDict.has_key(attrName): etisserant@0: del inputAttrDict[attrName] etisserant@0: else: etisserant@0: if attrDict["use"] == "required": etisserant@0: self._addError ("Attribute '%s' is missing for tag %s!" %(attrName, inputNode.getTagName()), inputNode) etisserant@0: elif attrDict["use"] == "optional": etisserant@0: if attrDict.has_key("default"): etisserant@0: inputNode.setAttribute(attrName, attrDict["default"]) etisserant@0: if attrDict.has_key("fixed"): etisserant@0: if inputNode.getAttribute(attrName) != attrDict["fixed"]: etisserant@0: self._addError ("Attribute '%s' must have fixed value '%s'!" %(attrName, attrDict["fixed"]), inputNode) etisserant@0: etisserant@0: if inputNode.hasAttribute(attrName): etisserant@0: if attrDict["use"] == "prohibited": etisserant@0: self._addError ("Attribute '%s' is prohibited in this context!" %(attrName), inputNode) etisserant@0: else: etisserant@0: attributeValue = inputNode.getAttribute(attrName) etisserant@0: try: etisserant@0: simpleTypeReturnDict = {} etisserant@0: if attrDict.has_key("type"): etisserant@0: self.simpleTypeVal.checkSimpleType (attrName, attrDict["type"], attributeValue, simpleTypeReturnDict) etisserant@0: else: etisserant@0: typedefNode = validAttribute.getFirstChildNS(self.xsdNSAlias, "simpleType") etisserant@0: if typedefNode != None: etisserant@0: self.simpleTypeVal.checkSimpleTypeDef (typedefNode, attrName, attributeValue, simpleTypeReturnDict) etisserant@0: else: etisserant@0: pass # default if no type attribute is specified etisserant@0: etisserant@0: if simpleTypeReturnDict.has_key("adaptedAttrValue"): etisserant@0: inputNode.setAttribute(attrName, simpleTypeReturnDict["adaptedAttrValue"]) etisserant@0: etisserant@0: except xsvalSimpleTypes.SimpleTypeError, errstr: etisserant@0: self._addError (str(errstr), inputNode) etisserant@0: etisserant@0: for inputAttribute in inputAttrDict.keys(): etisserant@0: # TODO: adapt for using namespaces!! etisserant@0: if self.xmlIf.extractLocalName(inputAttribute) in ("noNamespaceSchemaLocation", "schemaLocation"): etisserant@0: del inputAttrDict[inputAttribute] etisserant@0: etisserant@0: for inputAttribute in inputAttrDict.keys(): etisserant@0: if inputAttribute == "nil": etisserant@0: self._addError ("Tag '%s' hasn't been defined as nillable!" %(inputNode.getTagName()), inputNode) etisserant@0: else: etisserant@0: self._addError ("Unexpected attribute '%s' in Tag '%s'!" %(inputAttribute, inputNode.getTagName()), inputNode) etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # validate unique and key definition etisserant@0: # etisserant@0: def _checkIdentityConstraint (self, identityConstrNode, inputElement, isKey): etisserant@0: identConstrName = identityConstrNode.getAttribute ("name") etisserant@0: selectorXPathNode = identityConstrNode.getFirstChildNS (self.xsdNSAlias, "selector") etisserant@0: selectorNodeList, dummy = self._getXPath (inputElement, selectorXPathNode.getAttribute("xpath"), self.inputNSAlias) etisserant@0: etisserant@0: valueDict = {} etisserant@0: for selectorNode in selectorNodeList: etisserant@0: fieldXPathNodeList = identityConstrNode.getChildrenNS (self.xsdNSAlias, "field") etisserant@0: keyValue = [] etisserant@0: for fieldXPathNode in fieldXPathNodeList: etisserant@0: fieldXPath = fieldXPathNode.getAttribute("xpath") etisserant@0: fieldNodeList, fieldAttributeList = self._getXPath (selectorNode, fieldXPath, self.inputNSAlias, isKey) etisserant@0: if len(fieldNodeList) > 1 or len(fieldAttributeList) > 1: etisserant@0: self._addError ("The field xPath of identity constraint '%s' must evaluate to exactly 0 or 1 node!" %(identConstrName), fieldXPathNode) etisserant@0: return etisserant@0: etisserant@0: # TODO: unique and key check currently only on string base etisserant@0: for fieldNode in fieldNodeList: etisserant@0: keyValue.append (fieldNode.getElementValue ()) etisserant@0: etisserant@0: for attrValue in fieldAttributeList: etisserant@0: keyValue.append (attrValue) etisserant@0: etisserant@0: if keyValue != []: etisserant@0: keyValue = tuple(keyValue) etisserant@0: if not valueDict.has_key (keyValue): etisserant@0: valueDict[keyValue] = 1 etisserant@0: self.xsdIdentityConstrDict[identConstrName]["ValueDict"][keyValue] = 1 etisserant@0: else: etisserant@0: self._addError ("Duplicate identity constraint values '%s' found for identity contraint '%s'!" %(keyValue, identConstrName), selectorNode) etisserant@0: etisserant@0: ######################################## etisserant@0: # validate unique and key definition etisserant@0: # etisserant@0: def _checkKeyRefConstraint (self, keyrefNode, inputElement): etisserant@0: keyRefName = keyrefNode.getAttribute ("name") etisserant@0: keyReference = keyrefNode.getAttribute ("refer") etisserant@0: if not self.xsdIdentityConstrDict.has_key (keyReference): etisserant@0: self._addError ("keyref refers unknown key '%s'!" %(keyReference), keyrefNode) etisserant@0: return etisserant@0: etisserant@0: selectorXPathNode = keyrefNode.getFirstChildNS (self.xsdNSAlias, "selector") etisserant@0: selectorNodeList, dummy = self._getXPath (inputElement, selectorXPathNode.getAttribute("xpath"), self.inputNSAlias) etisserant@0: etisserant@0: for selectorNode in selectorNodeList: etisserant@0: fieldXPathNodeList = keyrefNode.getChildrenNS(self.xsdNSAlias, "field") etisserant@0: keyValue = [] etisserant@0: for fieldXPathNode in fieldXPathNodeList: etisserant@0: fieldXPath = fieldXPathNode.getAttribute("xpath") etisserant@0: fieldNodeList, fieldAttributeList = self._getXPath (selectorNode, fieldXPath, self.inputNSAlias, "keyref") etisserant@0: if len(fieldNodeList) > 1 or len(fieldAttributeList) > 1: etisserant@0: self._addError ("The field xPath of keyref '%s' must evaluate to exactly 0 or 1 node!" %(keyRefName), fieldXPathNode) etisserant@0: return etisserant@0: etisserant@0: # TODO: unique and key check currently only on string base etisserant@0: for fieldNode in fieldNodeList: etisserant@0: keyValue.append(fieldNode.getElementValue()) etisserant@0: etisserant@0: for attrValue in fieldAttributeList: etisserant@0: keyValue.append(attrValue) etisserant@0: etisserant@0: keyValue = tuple(keyValue) etisserant@0: if not self.xsdIdentityConstrDict[keyReference]["ValueDict"].has_key (keyValue): etisserant@0: self._addError ("Element value '%s' does not match key type '%s'!" %(keyValue, keyReference), selectorNode) etisserant@0: etisserant@0: ######################################## etisserant@0: # retrieve nodes/attributes specified by given xPath etisserant@0: # etisserant@0: def _getXPath (self, node, xPath, defaultNamespace, identityConstraint=None): etisserant@0: try: etisserant@0: nodeList, attributeList = node.getXPathList (xPath, defaultNamespace) etisserant@0: except IOError, errstr: etisserant@0: self._addError (errstr, node) etisserant@0: nodeList = attributeList = [] etisserant@0: etisserant@0: if nodeList == [] and attributeList == []: etisserant@0: if identityConstraint == "key": etisserant@0: self.errorHandler.addError ("Key is missing! XPath = '%s'!" %(xPath), node) etisserant@0: elif identityConstraint in ("unique", "keyref"): etisserant@0: self.errorHandler.addWarning ("Identity constraint is missing! XPath = '%s'!" %(xPath), node) etisserant@0: etisserant@0: return nodeList, attributeList etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # define own exception for XML schema validation errors etisserant@0: # etisserant@0: class TagException (StandardError): etisserant@0: def __init__ (self, errstr="", node=None, endTag=0): etisserant@0: self.node = node etisserant@0: self.errstr = errstr etisserant@0: self.endTag = endTag etisserant@0: StandardError.__init__(self) etisserant@0: