etisserant@0: # etisserant@0: # minixsv, Release 0.3 etisserant@0: # file: xsvalSchema.py etisserant@0: # etisserant@0: # Derived validator class (for validation of schema files) 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: from xsvalBase import XsValBase etisserant@0: etisserant@0: ########################################################### etisserant@0: # Derived validator class for validating one input schema file against the XML rules file etisserant@0: etisserant@0: class XsValSchema (XsValBase): etisserant@0: etisserant@0: ######################################## etisserant@0: # overloaded validate method etisserant@0: # etisserant@0: def validate (self, inputTree, xsdTree): etisserant@0: XsValBase.validate(self, inputTree, xsdTree) etisserant@0: self._checkSchemaSecondLevel() etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # additional checks for schema files which are not covered by "xsStructs.xsd" etisserant@0: # etisserant@0: def _checkSchemaSecondLevel(self): etisserant@0: self._checkElementNodesSecondLevel() etisserant@0: self._checkGroupNodesSecondLevel() etisserant@0: self._checkAttrGroupNodesSecondLevel() etisserant@0: self._checkAttributeNodesSecondLevel() etisserant@0: etisserant@0: self._checkSimpleTypesSecondLevel() etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # additional checks for element nodes etisserant@0: # etisserant@0: def _checkElementNodesSecondLevel(self): etisserant@0: self.inputElementDict = {} etisserant@0: for inputNode in self.inputRoot.getChildrenNS(self.inputNSAlias, "element"): etisserant@0: self.inputElementDict[inputNode.getAttribute("name")] = inputNode etisserant@0: etisserant@0: elementNodes = self.inputRoot.getElementsByTagNameNS (self.inputNSAlias, "element") etisserant@0: for elementNode in elementNodes: etisserant@0: if not elementNode.hasAttribute("name") and not elementNode.hasAttribute("ref"): etisserant@0: self._addError ("Element must have 'name' or 'ref' attribute!", elementNode) etisserant@0: continue etisserant@0: etisserant@0: if elementNode.hasAttribute("name") and elementNode.hasAttribute("ref"): etisserant@0: self._addError ("Element must not have 'name' and 'ref' attribute!", elementNode) etisserant@0: continue etisserant@0: etisserant@0: if elementNode.hasAttribute("ref"): etisserant@0: elementRef = self.xmlIf.extractLocalName(elementNode.getAttribute("ref")) etisserant@0: if not self.inputElementDict.has_key(elementRef): etisserant@0: self._addError ("Reference to undefined element '%s'!" %(elementRef), elementNode) etisserant@0: etisserant@0: complexTypeNode = elementNode.getFirstChildNS (self.inputNSAlias, "complexType") etisserant@0: simpleTypeNode = elementNode.getFirstChildNS (self.inputNSAlias, "simpleType") etisserant@0: if elementNode.hasAttribute("type") and (complexTypeNode != None or simpleTypeNode != None): etisserant@0: self._addError ("Element has type attribute and type definition!", elementNode) etisserant@0: if not elementNode.hasAttribute("type") and complexTypeNode == None and simpleTypeNode == None: etisserant@0: self._addWarning ("Element has no type attribute and no type definition!", elementNode) etisserant@0: etisserant@0: minOccurs = elementNode.getAttributeOrDefault("minOccurs", "1") etisserant@0: maxOccurs = elementNode.getAttributeOrDefault("maxOccurs", "1") etisserant@0: if maxOccurs != "unbounded": etisserant@0: if string.atoi(minOccurs) > string.atoi(maxOccurs): etisserant@0: self._addError ("Attribute minOccurs > maxOccurs!", elementNode) etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # additional checks for group nodes etisserant@0: # etisserant@0: def _checkGroupNodesSecondLevel(self): etisserant@0: self.inputGroupDict = {} etisserant@0: for groupNode in self.inputRoot.getChildrenNS(self.inputNSAlias, "group"): etisserant@0: self.inputGroupDict[groupNode.getAttribute("name")] = groupNode etisserant@0: etisserant@0: groupNodes = self.inputRoot.getElementsByTagNameNS (self.inputNSAlias, "group") etisserant@0: for groupNode in groupNodes: etisserant@0: if groupNode.hasAttribute("ref"): etisserant@0: groupRef = self.xmlIf.extractLocalName(groupNode.getAttribute("ref")) etisserant@0: if not self.inputGroupDict.has_key(groupRef): etisserant@0: self._addError ("Reference to undefined group '%s'!" %(groupRef), groupNode) etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # additional checks for attributeGroup nodes etisserant@0: # etisserant@0: def _checkAttrGroupNodesSecondLevel(self): etisserant@0: self.inputAttrGroupDict = {} etisserant@0: for attrGroupNode in self.inputRoot.getChildrenNS(self.inputNSAlias, "attrGroup"): etisserant@0: self.inputAttrGroupDict[attrGroupNode.getAttribute("name")] = attrGroupNode etisserant@0: etisserant@0: attrGroupNodes = self.inputRoot.getElementsByTagNameNS (self.inputNSAlias, "attrGroup") etisserant@0: for attrGroupNode in attrGroupNodes: etisserant@0: if attrGroupNode.hasAttribute("ref"): etisserant@0: attrGroupRef = self.xmlIf.extractLocalName(attrGroupNode.getAttribute("ref")) etisserant@0: if not self.inputAttrGroupDict.has_key(attrGroupRef): etisserant@0: self._addError ("Reference to undefined attribute group '%s'!" %(attrGroupRef), attrGroupNode) etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # additional checks for attribute nodes etisserant@0: # etisserant@0: def _checkAttributeNodesSecondLevel(self): etisserant@0: attributeNodes = self.inputRoot.getElementsByTagNameNS (self.inputNSAlias, "attribute") etisserant@0: for attributeNode in attributeNodes: etisserant@0: if not attributeNode.hasAttribute("name") and not attributeNode.hasAttribute("ref"): etisserant@0: self._addError ("Attribute must have 'name' or 'ref' attribute!", attributeNode) etisserant@0: continue etisserant@0: etisserant@0: if attributeNode.getAttribute("use") == "required" and attributeNode.hasAttribute("default"): etisserant@0: self._addError ("Attribute 'default' is not allowed, because 'use' is 'required'!", attributeNode) etisserant@0: elif attributeNode.hasAttribute("default") and attributeNode.hasAttribute("fixed"): etisserant@0: self._addError ("Attribute must not have 'default' AND 'fixed' attribute!", attributeNode) etisserant@0: etisserant@0: etisserant@0: ######################################## etisserant@0: # additional checks for simple types etisserant@0: # etisserant@0: def _checkSimpleTypesSecondLevel(self): etisserant@0: restrictionNodes, dummy = self.inputRoot.getXPathList (".//simpleType/restriction", self.inputNSAlias) etisserant@0: for restrictionNode in restrictionNodes: etisserant@0: if not restrictionNode.hasAttribute("base") and restrictionNode.getFirstChildNS (self.inputNSAlias, "simpleType") == None: etisserant@0: self._addError ("Simple type restriction must have 'base' attribute or 'simpleType' child tag!", restrictionNode) etisserant@0: etisserant@0: minExcl = restrictionNode.getFirstChildNS(self.inputNSAlias, "minExclusive") etisserant@0: minIncl = restrictionNode.getFirstChildNS(self.inputNSAlias, "minInclusive") etisserant@0: if minExcl != None and minIncl != None: etisserant@0: self._addError ("Restriction attributes 'minExclusive' and 'minInclusive' cannot be defined together!", restrictionNode) etisserant@0: maxExcl = restrictionNode.getFirstChildNS(self.inputNSAlias, "maxExclusive") etisserant@0: maxIncl = restrictionNode.getFirstChildNS(self.inputNSAlias, "maxInclusive") etisserant@0: if maxExcl != None and maxIncl != None: etisserant@0: self._addError ("Restriction attributes 'maxExclusive' and 'maxInclusive' cannot be defined together!", restrictionNode) etisserant@0: etisserant@0: listNodes = self.inputRoot.getElementsByTagNameNS (self.inputNSAlias, "list") etisserant@0: for listNode in listNodes: etisserant@0: if not listNode.hasAttribute("itemType") and restrictionNode.getFirstChildNS (self.inputNSAlias, "simpleType") == None: etisserant@0: self._addError ("List type must have 'itemType' attribute or 'simpleType' child tag!", listNode) etisserant@0: etisserant@0: