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.
 
 
 
 
 

1280 lines
64 KiB

#
# minixsv, Release 0.9.0
# file: xsvalBase.py
#
# XML schema validator base class
#
# history:
# 2004-10-07 rl created
# 2006-08-18 rl W3C testsuite passed for supported features
# 2007-06-14 rl Features for release 0.8 added, several bugs fixed
#
# Copyright (c) 2004-2008 by Roland Leuthe. All rights reserved.
#
# --------------------------------------------------------------------
# The minixsv XML schema validator is
#
# Copyright (c) 2004-2008 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 string
import copy
from ..minixsv import *
from ..genxmlif.xmlifUtils import collapseString, convertToAbsUrl, NsNameTupleFactory, NsNameTuple
from xsvalSimpleTypes import XsSimpleTypeVal, SimpleTypeError
wxsdTree = None
wxsdLookupDict = {}
##########################################################
# Validator class for validating one input file against one XML schema file
class XsValBase:
def __init__(self, xmlIf, errorHandler, verbose):
self.xmlIf = xmlIf
self.errorHandler = errorHandler
self.verbose = verbose
self._raiseError = self.errorHandler.raiseError
self._addError = self.errorHandler.addError
self._addWarning = self.errorHandler.addWarning
self._addInfo = self.errorHandler.addInfo
self.checkKeyrefList = []
def unlink(self):
self.simpleTypeVal.unlink()
########################################
# validate inputTree against xsdTree
#
def validate (self, inputTree, xsdTreeList):
self.inputTree = inputTree
self.inputRoot = self.inputTree.getRootNode()
self.inputNsURI = self.inputRoot.getNamespaceURI()
self.inputNsPrefix = self.inputRoot.getNsPrefix(self.inputRoot.getNsName())
if self.inputNsPrefix != None:
self.inputNsPrefixString = "%s:" %(self.inputNsPrefix)
else:
self.inputNsPrefixString = ""
# initialise lookup dictionary
global wxsdLookupDict
if wxsdLookupDict == {}:
wxsdLookupDict = {"ElementDict":{}, "TypeDict":{}, "GroupDict":{},
"AttrGroupDict":{}, "AttributeDict":{}, "IdentityConstrDict":{}}
self._importWellknownSchemas(wxsdLookupDict)
self.xsdLookupDict = {"ElementDict": wxsdLookupDict["ElementDict"].copy(),
"TypeDict": wxsdLookupDict["TypeDict"].copy(),
"GroupDict": wxsdLookupDict["GroupDict"].copy(),
"AttrGroupDict": wxsdLookupDict["AttrGroupDict"].copy(),
"AttributeDict": wxsdLookupDict["AttributeDict"].copy(),
"IdentityConstrDict": wxsdLookupDict["IdentityConstrDict"].copy()}
self.xsdElementDict = self.xsdLookupDict["ElementDict"]
self.xsdTypeDict = self.xsdLookupDict["TypeDict"]
self.xsdGroupDict = self.xsdLookupDict["GroupDict"]
self.xsdAttrGroupDict = self.xsdLookupDict["AttrGroupDict"]
self.xsdAttributeDict = self.xsdLookupDict["AttributeDict"]
self.xsdIdentityConstrDict = self.xsdLookupDict["IdentityConstrDict"]
self.xsdIdDict = {}
self.xsdIdRefDict = {}
self.idAttributeForType = None
for xsdTree in xsdTreeList:
xsdRoot = xsdTree.getRootNode()
# TODO: The following member may differ if several schema files are used!!
self.xsdNsURI = xsdRoot.getNamespaceURI()
self.xsdIncludeDict = {xsdRoot.getAbsUrl():1,}
if xsdRoot.getFilePath() != os.path.join (MINIXSV_DIR, "XMLSchema.xsd"):
self._initInternalAttributes (xsdRoot)
self._updateLookupTables(xsdRoot, self.xsdLookupDict)
self._includeAndImport (xsdTree, xsdTree, self.xsdIncludeDict, self.xsdLookupDict)
self.simpleTypeVal = XsSimpleTypeVal(self)
inputRootNsName = self.inputRoot.getNsName()
if self.xsdElementDict.has_key(inputRootNsName):
# start recursive schema validation
try:
self._checkElementTag (self.xsdElementDict[inputRootNsName], self.inputRoot, (self.inputRoot,), 0)
except TagException, errInst:
self._addError (errInst.errstr, errInst.node, errInst.endTag)
if not self.errorHandler.hasErrors():
# validate IDREFs
for idref in self.xsdIdRefDict.keys():
if not self.xsdIdDict.has_key(idref):
self._addError ("There is no ID/IDREF binding for IDREF %s" %repr(idref), self.xsdIdRefDict[idref])
# validate keyrefs
for inputElement, keyrefNode in self.checkKeyrefList:
self._checkKeyRefConstraint (keyrefNode, inputElement)
else:
self._raiseError ("Used root tag %s not found in schema file(s)!"
%repr(inputRootNsName), self.inputRoot)
########################################
# include/import all files specified in the schema file
# import well-known schemas
#
def _includeAndImport (self, baseTree, tree, includeDict, lookupDict):
self._expandIncludes (baseTree, tree, includeDict, lookupDict)
self._expandRedefines (baseTree, tree, includeDict, lookupDict)
self._expandImports (baseTree, tree, includeDict, lookupDict)
########################################
# expand include directives
#
def _expandIncludes (self, baseTree, tree, includeDict, lookupDict):
rootNode = tree.getRootNode()
namespaceURI = rootNode.getNamespaceURI()
for includeNode in rootNode.getChildrenNS(namespaceURI, "include"):
includeUrl = includeNode.getAttribute("schemaLocation")
expNamespace = rootNode.getAttributeOrDefault("targetNamespace", None)
self._includeSchemaFile (baseTree, tree, includeNode, expNamespace, includeUrl, includeNode.getBaseUrl(), includeDict, lookupDict,
adaptTargetNamespace=1)
rootNode.removeChild (includeNode)
########################################
# expand redefine directives
#
def _expandRedefines (self, baseTree, tree, includeDict, lookupDict):
rootNode = tree.getRootNode()
namespaceURI = rootNode.getNamespaceURI()
for redefineNode in rootNode.getChildrenNS(namespaceURI, "redefine"):
redefineUrl = redefineNode.getAttribute("schemaLocation")
expNamespace = rootNode.getAttributeOrDefault("targetNamespace", None)
self._includeSchemaFile (baseTree, tree, redefineNode, expNamespace, redefineUrl, redefineNode.getBaseUrl(), includeDict, lookupDict,
adaptTargetNamespace=1)
# fill lookup tables with redefined definitions
for childNode in redefineNode.getChildren():
redefineNode.removeChild(childNode)
rootNode.insertBefore(childNode, redefineNode)
if childNode.getLocalName() in ("complexType", "simpleType"):
xsdDict = self.xsdLookupDict["TypeDict"]
elif childNode.getLocalName() in ("attributeGroup"):
xsdDict = self.xsdLookupDict["AttrGroupDict"]
elif childNode.getLocalName() in ("group"):
xsdDict = self.xsdLookupDict["GroupDict"]
elif childNode.getLocalName() in ("annotation"):
continue
else:
self._addError ("%s not allowed as child of 'redefine'!" %repr(childNode.getLocalName()), childNode)
continue
redefType = NsNameTuple ( (expNamespace, childNode.getAttribute("name")) )
if xsdDict.has_key(redefType):
orgRedefType = NsNameTuple( (expNamespace, redefType[1]+"__ORG") )
if not xsdDict.has_key(orgRedefType):
xsdDict[orgRedefType] = xsdDict[redefType]
# else:
# self._addError ("Duplicate component %s found within 'redefine'!" %repr(redefType), childNode)
xsdDict[redefType] = childNode
else:
self._addError ("Type %s not found in imported schema file!" %(repr(redefType)), childNode)
dummy, attrNodes, attrNsNameFirst = childNode.getXPathList (".//@base | .//@ref" % vars())
for attrNode in attrNodes:
if attrNode.hasAttribute("base"):
attribute = "base"
elif attrNode.hasAttribute("ref"):
attribute = "ref"
if attrNode.getQNameAttribute(attribute) == redefType:
attrNode[attribute] = attrNode[attribute] + "__ORG"
rootNode.removeChild (redefineNode)
########################################
# expand import directives
#
def _expandImports (self, baseTree, tree, includeDict, lookupDict):
rootNode = tree.getRootNode()
namespaceURI = rootNode.getNamespaceURI()
for includeNode in rootNode.getChildrenNS(namespaceURI, "import"):
expNamespace = includeNode.getAttributeOrDefault("namespace", None)
if expNamespace == self._getTargetNamespace(includeNode):
self._addError ("Target namespace and target namespace of imported schema must not be the same!", includeNode)
continue
includeUrl = includeNode.getAttributeOrDefault("schemaLocation", None)
if expNamespace != None and includeUrl == None:
includeUrl = expNamespace + ".xsd"
if includeUrl != None:
if expNamespace not in (XML_NAMESPACE, XSI_NAMESPACE):
self._includeSchemaFile (baseTree, tree, includeNode, expNamespace, includeUrl, includeNode.getBaseUrl(), includeDict, lookupDict)
else:
self._addError ("schemaLocation attribute for import directive missing!", includeNode)
rootNode.removeChild (includeNode)
########################################
# import well-known schema files
#
def _importWellknownSchemas (self, lookupDict):
global wxsdTree
file = os.path.join (MINIXSV_DIR, "XMLSchema.xsd")
wxsdTree = self.xmlIf.parse (file)
self._initInternalAttributes (wxsdTree.getRootNode())
self._updateLookupTables (wxsdTree.getRootNode(), lookupDict)
for schemaFile in ("datatypes.xsd", "xml.xsd", "XMLSchema-instance.xsd"):
file = os.path.join (MINIXSV_DIR, schemaFile)
subTree = self._parseIncludeSchemaFile(wxsdTree, wxsdTree, None, file, None)
self._updateLookupTables (subTree.getRootNode(), lookupDict)
########################################
# include/import a schema file
#
def _includeSchemaFile (self, baseTree, tree, nextSibling, expNamespace, includeUrl, baseUrl, includeDict, lookupDict,
adaptTargetNamespace=0):
if includeUrl == None:
self._raiseError ("Schema location attribute missing!", nextSibling)
absUrl = convertToAbsUrl (includeUrl, baseUrl)
if includeDict.has_key (absUrl):
# file already included
return
if self.verbose:
print "including %s..." %(includeUrl)
rootNode = tree.getRootNode()
subTree = self._parseIncludeSchemaFile(baseTree, tree, nextSibling, includeUrl, baseUrl)
includeDict[absUrl] = 1
stRootNode = subTree.getRootNode()
if rootNode.getNsName() != stRootNode.getNsName():
self._raiseError ("Root tag of file %s does not match!" %repr(includeUrl), nextSibling)
if stRootNode.hasAttribute("targetNamespace"):
if expNamespace != stRootNode["targetNamespace"]:
self._raiseError ("Target namespace of file %s does not match!" %repr(includeUrl), nextSibling)
else:
if expNamespace != None:
if adaptTargetNamespace:
# if no target namespace is specified in the included file
# the target namespace of the parent file is taken
stRootNode["targetNamespace"] = expNamespace
for stDescNode in stRootNode.getIterator():
stDescNode.curNs.append((EMPTY_PREFIX,expNamespace))
else:
self._raiseError ("Target namespace of file %s does not match!" %repr(includeUrl), nextSibling)
self._updateLookupTables (subTree.getRootNode(), lookupDict)
self._includeAndImport (baseTree, subTree, includeDict, lookupDict)
if includeUrl not in (r"C:\Program Files\Python24\Lib\site-packages\minixsv\xml.xsd",
r"C:\Program Files\Python24\Lib\site-packages\minixsv\XMLSchema.xsd",
r"C:\Program Files\Python24\Lib\site-packages\minixsv\XMLSchema-instance.xsd"):
rootNode.insertSubtree (nextSibling, subTree, insertSubTreeRootNode=0)
def _parseIncludeSchemaFile (self, baseTree, tree, nextSibling, includeUrl, baseUrl):
# try to parse included schema file
try:
subTree = self.xmlIf.parse (includeUrl, baseUrl, baseTree.getTree())
self._initInternalAttributes (subTree.getRootNode())
except IOError, errInst:
self._raiseError ("%s" %str(errInst), nextSibling)
except SyntaxError, e:
# FIXME: sometimes an URLError is catched instead of a standard IOError
try:
dummy = e.errno
except:
raise IOError, e
if e.errno in (2, "socket error", "url error"): # catch IOError: No such file or directory
self._raiseError ("%s: '%s'" %(e.strerror, e.filename), nextSibling)
else:
raise
return subTree
########################################
# update lookup dictionaries used during validation
#
def _updateLookupTables (self, rootNode, lookupDict):
schemaTagDict = {"element" : "ElementDict",
"complexType": "TypeDict",
"simpleType" : "TypeDict",
"group" : "GroupDict",
"attributeGroup": "AttrGroupDict",
"attribute" : "AttributeDict",
}
# retrieve all schema tags
for localName, lookupDictName in schemaTagDict.items():
for node in rootNode.getChildrenNS(XSD_NAMESPACE, localName):
targetNamespace = self._getTargetNamespace(node)
if not lookupDict[lookupDictName].has_key((targetNamespace, node.getAttribute("name"))):
lookupDict[lookupDictName][(targetNamespace, node.getAttribute("name"))] = node
# retrieve all identity constraints
for identConstrTagName in ("unique", "key", "keyref"):
identConstrNodeList = rootNode.getElementsByTagNameNS (XSD_NAMESPACE, identConstrTagName)
for identConstrNode in identConstrNodeList:
targetNamespace = self._getTargetNamespace(identConstrNode)
identConstrNsLocalName = NsNameTupleFactory ( (targetNamespace, identConstrNode.getAttribute("name")) )
if not lookupDict["IdentityConstrDict"].has_key(identConstrNsLocalName):
lookupDict["IdentityConstrDict"][identConstrNsLocalName] = {"Node": identConstrNode, "ValueDict":{}}
# else:
# self._addError ("Duplicate identity constraint name %s found!"
# %(repr(identConstrNsLocalName)), identConstrNode)
########################################
# validate inputNode against complexType node
#
def _initInternalAttributes (self, rootNode):
# set schema root node for all descendant nodes
if not rootNode.getSchemaRootNode():
for node in rootNode.getIterator():
node.setSchemaRootNode(rootNode)
########################################
# validate inputNode against complexType node
#
def _checkComplexTypeTag (self, xsdParentNode, xsdNode, inputNode, inputChildIndex, usedAsBaseType=None):
baseTypeAttributes = {}
complexContentNode = xsdNode.getFirstChildNS(self.xsdNsURI, "complexContent")
simpleContentNode = xsdNode.getFirstChildNS(self.xsdNsURI, "simpleContent")
if complexContentNode != None:
inputChildIndex, baseTypeAttributes = self._checkComplexContentTag (xsdParentNode, complexContentNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes)
elif simpleContentNode != None:
inputChildIndex, baseTypeAttributes = self._checkSimpleContentTag (xsdParentNode, simpleContentNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes)
else:
inputChildIndex, baseTypeAttributes = self._checkComplexTypeContent (xsdParentNode, xsdNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes)
if usedAsBaseType == None:
self._checkMixed (xsdParentNode, xsdNode, inputNode)
return inputChildIndex, baseTypeAttributes
def _checkComplexContentTag (self, xsdParentNode, xsdNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes):
extensionNode = xsdNode.getFirstChildNS(self.xsdNsURI, "extension")
if extensionNode != None:
inputChildIndex, baseTypeAttributes = self._checkExtensionComplexContent (xsdParentNode, extensionNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes)
else:
restrictionNode = xsdNode.getFirstChildNS(self.xsdNsURI, "restriction")
if restrictionNode != None:
inputChildIndex, baseTypeAttributes = self._checkRestrictionComplexContent (xsdParentNode, restrictionNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes)
else:
raise AttributeError, "RestrictionNode not found!"
# if usedAsBaseType == None:
# self._checkMixed (xsdNode, inputNode)
return inputChildIndex, baseTypeAttributes
def _checkSimpleContentTag (self, xsdParentNode, xsdNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes):
if inputNode.getAttribute( (XSI_NAMESPACE, "nil") ) == "true":
if inputNode.getChildren() != [] or collapseString(inputNode.getElementValue()) != "":
self._addError ("Element must be empty (xsi:nil='true')(1)!" , inputNode, 0)
extensionNode = xsdNode.getFirstChildNS(self.xsdNsURI, "extension")
if extensionNode != None:
inputChildIndex, baseTypeAttributes = self._checkExtensionSimpleContent (xsdParentNode, extensionNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes)
else:
restrictionNode = xsdNode.getFirstChildNS(self.xsdNsURI, "restriction")
if restrictionNode != None:
inputChildIndex, baseTypeAttributes = self._checkRestrictionSimpleContent (xsdParentNode, xsdNode, restrictionNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes)
return inputChildIndex, baseTypeAttributes
def _checkExtensionComplexContent (self, xsdParentNode, xsdNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes):
baseNsName = xsdNode.getQNameAttribute("base")
if usedAsBaseType == None:
extUsedAsBaseType = "extension"
else:
extUsedAsBaseType = usedAsBaseType
inputChildIndex, baseTypeAttributes = self._checkComplexTypeTag (xsdParentNode, self.xsdTypeDict[baseNsName], inputNode, inputChildIndex, extUsedAsBaseType)
inputChildIndex, baseTypeAttributes = self._checkComplexTypeContent (xsdParentNode, xsdNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes)
return inputChildIndex, baseTypeAttributes
def _checkExtensionSimpleContent (self, xsdParentNode, xsdNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes):
self._checkSimpleType (xsdNode, "base", inputNode, inputNode.getTagName(), inputNode.getElementValue(), None, checkAttribute=0)
if xsdNode.hasAttribute("BaseTypes"):
xsdParentNode["BaseTypes"] = xsdNode["BaseTypes"]
inputChildIndex, baseTypeAttributes = self._checkSimpleTypeContent (xsdParentNode, xsdNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes)
return inputChildIndex, baseTypeAttributes
def _checkRestrictionComplexContent (self, xsdParentNode, xsdNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes):
# first check against base type (retrieve only the base type attributes)
baseNsName = xsdNode.getQNameAttribute("base")
inputChildIndex, baseTypeAttributes = self._checkComplexTypeTag (xsdParentNode, self.xsdTypeDict[baseNsName], inputNode, inputChildIndex, "restriction")
# then check input against derived complex type
inputChildIndex, baseTypeAttributes = self._checkComplexTypeContent (xsdParentNode, xsdNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes)
return inputChildIndex, baseTypeAttributes
def _checkRestrictionSimpleContent (self, xsdParentNode, simpleContentNode, xsdNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes):
try:
simpleTypeReturnDict = {"BaseTypes":[], "primitiveType":None}
self.simpleTypeVal.checkSimpleTypeDef (inputNode, simpleContentNode, inputNode.getTagName(), inputNode.getElementValue(), simpleTypeReturnDict, idCheck=1)
xsdNode["BaseTypes"] = string.join (simpleTypeReturnDict["BaseTypes"], " ")
except SimpleTypeError, errInst:
self._addError (errInst.args[0], inputNode)
inputChildIndex, baseTypeAttributes = self._checkSimpleTypeContent (xsdParentNode, xsdNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes)
return inputChildIndex, baseTypeAttributes
def _checkComplexTypeContent (self, xsdParentNode, xsdNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes):
if inputNode.getAttribute((XSI_NAMESPACE, "nil")) == "true":
if inputNode.getChildren() != [] or collapseString(inputNode.getElementValue()) != "":
self._addError ("Element must be empty (xsi:nil='true')(2)!" , inputNode, 0)
else:
childTags = inputNode.getChildren()
if usedAsBaseType in (None, "extension"):
validChildTags = xsdNode.getChildren()
for validChildTag in validChildTags:
if validChildTag.getLocalName() not in ("attribute", "attributeGroup", "anyAttribute"):
inputChildIndex = self._checkParticle (validChildTag, inputNode, childTags, inputChildIndex)
if usedAsBaseType == None and inputChildIndex < len (childTags):
inputNsName = inputNode.getNsName()
childNsName = childTags[inputChildIndex].getNsName()
self._addError ("Unexpected or invalid child tag %s found in tag %s!"
%(repr(childNsName), repr(inputNsName)), childTags[inputChildIndex])
if usedAsBaseType in (None,):
self._checkAttributeTags (xsdParentNode, xsdNode, inputNode, baseTypeAttributes)
if usedAsBaseType in ("restriction", "extension"):
self._updateAttributeDict (xsdNode, baseTypeAttributes)
return inputChildIndex, baseTypeAttributes
def _checkSimpleTypeContent (self, xsdParentNode, xsdNode, inputNode, inputChildIndex, usedAsBaseType, baseTypeAttributes):
if inputNode.getChildren() != []:
raise TagException ("No child tags are allowed for element %s!" %repr(inputNode.getNsName()), inputNode)
if usedAsBaseType in (None,):
self._checkAttributeTags (xsdParentNode, xsdNode, inputNode, baseTypeAttributes)
if usedAsBaseType in ("restriction", "extension"):
self._updateAttributeDict (xsdNode, baseTypeAttributes)
return inputChildIndex, baseTypeAttributes
########################################
# validate mixed content (1)
#
def _checkMixed (self, xsdParentNode, xsdNode, inputNode):
if xsdNode.getAttributeOrDefault ("mixed", "false") == "false":
if not collapseString(inputNode.getElementValue()) in ("", " "):
self._addError ("Mixed content not allowed for %s!" %repr(inputNode.getTagName()), inputNode)
else: # mixed = true
self._checkUrType(xsdParentNode, inputNode)
########################################
# check ur-type
#
def _checkUrType (self, xsdNode, inputNode):
prefix = xsdNode.getPrefix()
if prefix:
xsdNode["__CONTENTTYPE__"] = "%s:string" %xsdNode.getPrefix()
else:
xsdNode["__CONTENTTYPE__"] = "string"
self._checkElementValue (xsdNode, "__CONTENTTYPE__", inputNode)
xsdNode.removeAttribute("__CONTENTTYPE__")
########################################
# validate inputNodeList against xsdNode
#
def _checkList (self, elementMethod, xsdNode, inputParentNode, inputNodeList, currIndex):
minOccurs = string.atoi(xsdNode.getAttributeOrDefault("minOccurs", "1"))
maxOccurs = xsdNode.getAttributeOrDefault("maxOccurs", "1")
if maxOccurs != "unbounded":
maxOccurs = string.atoi(maxOccurs)
else:
maxOccurs = -1
occurs = 0
while maxOccurs == -1 or occurs < maxOccurs:
try:
newIndex = elementMethod (xsdNode, inputParentNode, inputNodeList, currIndex)
occurs += 1
if newIndex > currIndex:
currIndex = newIndex
else:
break # no suitable element found
except TagException, errInst:
break
if occurs == 0 and minOccurs > 0:
raise errInst
elif occurs < minOccurs:
expInputTagName = xsdNode.getAttribute("name")
if expInputTagName == None:
expInputTagName = xsdNode.getQNameAttribute("ref")
raise TagException ("minOccurs (%d) of child tag %s in tag %s not available (only %d)!"
%(minOccurs, repr(expInputTagName), repr(inputParentNode.getTagName()), occurs), inputParentNode, 1)
return currIndex
########################################
# validate inputNode against element node
#
def _checkElementTag (self, xsdNode, inputParentNode, inputNodeList, currIndex):
if xsdNode.hasAttribute("ref"):
refNsName = xsdNode.getQNameAttribute("ref")
currIndex = self._checkElementTag (self.xsdElementDict[refNsName], inputParentNode, inputNodeList, currIndex)
else:
nameAttr = xsdNode.getAttribute ("name")
if currIndex >= len (inputNodeList):
raise TagException ("Missing child tag %s in tag %s!" %(repr(nameAttr), repr(inputParentNode.getTagName())), inputParentNode, 1)
inputNode = inputNodeList[currIndex]
if nameAttr != inputNode.getLocalName():
raise TagException ("Missing child tag %s in tag %s!" %(repr(nameAttr), repr(inputParentNode.getTagName())), inputNode, 0)
# store reference to XSD definition node
inputNode.setXsdNode(xsdNode)
currIndex = currIndex + 1
self._checkInputElementForm (xsdNode, nameAttr, inputNode)
if (xsdNode.getFirstChild() == None and
not xsdNode.hasAttribute("type") and
not inputNode.hasAttribute((XSI_NAMESPACE, "type")) ):
self._checkUrType(xsdNode, inputNode)
# ur-type => try to check children of input node
for inputChild in inputNode.getChildren():
try:
if self.xsdElementDict.has_key(inputChild.getNsName()):
self._checkElementTag (self.xsdElementDict[inputChild.getNsName()], inputNode, (inputChild,), 0)
except TagException, errInst:
self._addError (errInst.errstr, errInst.node, errInst.endTag)
return currIndex
complexTypeNode = xsdNode.getFirstChildNS (self.xsdNsURI, "complexType")
if not inputNode.hasAttribute((XSI_NAMESPACE, "type")):
typeNsName = xsdNode.getQNameAttribute ("type")
else:
# overloaded type is used
typeNsName = inputNode.getQNameAttribute((XSI_NAMESPACE, "type"))
if not self.xsdTypeDict.has_key(typeNsName):
self._addError ("Unknown overloaded type %s!" %(repr(typeNsName)), inputNode, 0)
return currIndex
if self.xsdTypeDict.has_key (typeNsName):
typeType = self.xsdTypeDict[typeNsName].getLocalName()
if typeType == "complexType":
complexTypeNode = self.xsdTypeDict[typeNsName]
# else simpleType => pass, handled later on
if complexTypeNode != None:
try:
self._checkComplexTypeTag (xsdNode, complexTypeNode, inputNode, 0)
except TagException, errInst:
self._addError (errInst.errstr, errInst.node, errInst.endTag)
return currIndex
else:
self._checkElementSimpleType (xsdNode, "type", inputNode)
# check unique attributes and keys
childUniqueDefList = xsdNode.getChildrenNS (self.xsdNsURI, "unique")
for childUniqueDef in childUniqueDefList:
self._checkIdentityConstraint (childUniqueDef, inputNode)
childKeyDefList = xsdNode.getChildrenNS (self.xsdNsURI, "key")
for childKeyDef in childKeyDefList:
self._checkIdentityConstraint (childKeyDef, inputNode)
childKeyrefDefList = xsdNode.getChildrenNS (self.xsdNsURI, "keyref")
for childKeyrefDef in childKeyrefDefList:
self.checkKeyrefList.append ((inputNode, childKeyrefDef))
return currIndex
########################################
# validate element inputNode against simple type definition
#
def _checkElementSimpleType (self, xsdNode, xsdTypeAttr, inputNode):
if inputNode.getChildren() != []:
raise TagException ("No child tags are allowed for element %s!" %(repr(inputNode.getNsName())), inputNode)
self._checkElementValue (xsdNode, xsdTypeAttr, inputNode)
self._checkAttributeTags (xsdNode, xsdNode, inputNode, {})
########################################
# validate inputNode against simple type definition
#
def _checkElementValue (self, xsdNode, xsdTypeAttr, inputNode):
fixedValue = xsdNode.getAttribute("fixed")
if inputNode.getAttribute((XSI_NAMESPACE, "nil")) == "true" and fixedValue != None:
self._addError ("There must be no fixed value for Element because xsi:nil='true' is specified!" , inputNode)
if inputNode.getAttribute((XSI_NAMESPACE, "nil")) != "true" and inputNode.getElementValue() == "":
if xsdNode.hasAttribute("default"):
inputNode.setElementValue(xsdNode["default"])
if fixedValue != None:
inputNode.setElementValue(fixedValue)
self._checkSimpleType (xsdNode, xsdTypeAttr, inputNode, inputNode.getTagName(), inputNode.getElementValue(), fixedValue, checkAttribute=0)
########################################
# validate inputNode against simple type definition
#
def _checkSimpleType (self, xsdNode, xsdTypeAttr, inputNode, attrName, attrValue, fixedValue, checkAttribute=0, checkId=1):
retValue = None
if checkAttribute == 0 and inputNode.hasAttribute((XSI_NAMESPACE, "nil")):
if (inputNode[(XSI_NAMESPACE, "nil")] == "true" and
collapseString(inputNode.getElementValue()) != ""):
self._addError ("Element must be empty (xsi:nil='true')(3)!" , inputNode, 0)
return retValue
try:
simpleTypeReturnDict = {"BaseTypes":[], "primitiveType":None}
fixedValueReturnDict = {"BaseTypes":[], "primitiveType":None}
simpleTypeNode = xsdNode.getFirstChildNS (self.xsdNsURI, "simpleType")
if simpleTypeNode != None:
self.simpleTypeVal.checkSimpleTypeDef (inputNode, simpleTypeNode, attrName, attrValue, simpleTypeReturnDict, checkId)
if fixedValue != None:
self.simpleTypeVal.checkSimpleTypeDef (inputNode, simpleTypeNode, attrName, fixedValue, fixedValueReturnDict, idCheck=0)
elif (xsdNode.getFirstChildNS (self.xsdNsURI, "complexType") != None and
xsdNode.getFirstChildNS (self.xsdNsURI, "complexType").getAttribute("mixed") == "false"):
self._addError ("Attribute %s requires a simple or mixed type!" %repr(attrName), inputNode)
else:
typeNsName = xsdNode.getQNameAttribute (xsdTypeAttr)
if typeNsName != (None, None):
self.simpleTypeVal.checkSimpleType (inputNode, attrName, typeNsName, attrValue, simpleTypeReturnDict, checkId)
# TODO: What to check if no type is specified for the element?
if fixedValue != None:
self.simpleTypeVal.checkSimpleType (inputNode, attrName, typeNsName, fixedValue, fixedValueReturnDict, idCheck=0)
xsdNode["BaseTypes"] = string.join (simpleTypeReturnDict["BaseTypes"], " ")
xsdNode["primitiveType"] = str(simpleTypeReturnDict["primitiveType"])
retValue = simpleTypeReturnDict
if simpleTypeReturnDict.has_key("wsAction"):
if checkAttribute:
attrValue = inputNode.processWsAttribute(attrName, simpleTypeReturnDict["wsAction"])
else:
attrValue = inputNode.processWsElementValue(simpleTypeReturnDict["wsAction"])
if fixedValue != None:
if fixedValueReturnDict.has_key("orderedValue"):
fixedValue = fixedValueReturnDict["orderedValue"]
elif fixedValueReturnDict.has_key("adaptedAttrValue"):
fixedValue = fixedValueReturnDict["adaptedAttrValue"]
if simpleTypeReturnDict.has_key("orderedValue"):
attrValue = simpleTypeReturnDict["orderedValue"]
if attrValue != fixedValue:
if checkAttribute:
self._addError ("Attribute %s must have fixed value %s!" %(repr(attrName), repr(fixedValue)), inputNode)
else:
self._addError ("Element must have fixed value %s!" %repr(fixedValue), inputNode)
except SimpleTypeError, errInst:
self._addError (errInst.args[0], inputNode)
return retValue
########################################
# validate inputNode against sequence node
#
def _checkSequenceTag (self, xsdNode, inputParentNode, inputNodeList, currIndex):
for xsdChildNode in xsdNode.getChildren():
currIndex = self._checkParticle (xsdChildNode, inputParentNode, inputNodeList, currIndex)
return currIndex
########################################
# validate inputNode against choice node
#
def _checkChoiceTag (self, xsdNode, inputParentNode, inputNodeList, currIndex):
childFound = 0
exceptionRaised = 0
for xsdChildNode in xsdNode.getChildren():
try:
newIndex = self._checkParticle (xsdChildNode, inputParentNode, inputNodeList, currIndex)
if newIndex > currIndex:
currIndex = newIndex
childFound = 1
break
else:
exceptionRaised = 0
except TagException, errInst:
exceptionRaised = 1
else:
if not childFound and exceptionRaised:
if currIndex < len(inputNodeList):
currNode = inputNodeList[currIndex]
endTag = 0
else:
currNode = inputParentNode
endTag = 1
raise TagException ("No suitable child tag for choice found!", currNode, endTag)
return currIndex
########################################
# validate inputNode against group node
#
def _checkGroupTag (self, xsdNode, inputParentNode, inputNodeList, currIndex):
if xsdNode.hasAttribute("ref"):
refNsName = xsdNode.getQNameAttribute("ref")
currIndex = self._checkGroupTag (self.xsdGroupDict[refNsName], inputParentNode, inputNodeList, currIndex)
else:
for xsdChildNode in xsdNode.getChildren():
currIndex = self._checkParticle (xsdChildNode, inputParentNode, inputNodeList, currIndex)
return currIndex
########################################
# validate inputNode against all node
#
def _checkAllTag (self, xsdNode, inputParentNode, inputNodeList, currIndex):
oldIndex = currIndex
xsdChildDict = {}
for xsdChildNode in xsdNode.getChildren():
if xsdChildNode.getNsName() != (XSD_NAMESPACE, "annotation"):
xsdChildDict[xsdChildNode] = 0
while (currIndex < len(inputNodeList)) and (0 in xsdChildDict.values()):
currNode = inputNodeList[currIndex]
for xsdChildNode in xsdChildDict.keys():
try:
newIndex = self._checkParticle (xsdChildNode, inputParentNode, inputNodeList, currIndex)
if newIndex == currIndex:
continue
except TagException, errInst:
continue
if xsdChildDict[xsdChildNode] == 0:
xsdChildDict[xsdChildNode] = 1
currIndex = newIndex
break
else:
raise TagException ("Ambiguous child tag %s found in all-group!" %repr(currNode.getTagName()), currNode)
else:
raise TagException ("Unexpected child tag %s for all-group found!" %repr(currNode.getTagName()), currNode)
for xsdChildNode, occurs in xsdChildDict.items():
if xsdChildNode.getAttributeOrDefault("minOccurs", "1") != "0" and occurs == 0:
raise TagException ("Child tag %s missing in all-group (%s)" %(repr(xsdChildNode.getAttribute("name")), repr(inputParentNode.getTagName())), inputParentNode)
return currIndex
########################################
# validate inputNode against any node
#
def _checkAnyTag (self, xsdNode, inputParentNode, inputNodeList, currIndex):
if currIndex >= len (inputNodeList):
raise TagException ("Missing child tag (anyTag) in tag %s!" %repr(inputParentNode.getTagName()), inputParentNode, 1)
inputNode = inputNodeList[currIndex]
inputNamespace = inputNode.getNamespaceURI()
self._checkWildcardElement (xsdNode, inputNode, inputNamespace)
currIndex = currIndex + 1
return currIndex
########################################
# validate inputNode against particle
#
def _checkParticle (self, xsdNode, inputParentNode, inputNodeList, currIndex):
xsdTagName = xsdNode.getLocalName()
if xsdTagName == "element":
currIndex = self._checkList (self._checkElementTag, xsdNode, inputParentNode, inputNodeList, currIndex)
elif xsdTagName == "choice":
currIndex = self._checkList (self._checkChoiceTag, xsdNode, inputParentNode, inputNodeList, currIndex)
elif xsdTagName == "sequence":
currIndex = self._checkList (self._checkSequenceTag, xsdNode, inputParentNode, inputNodeList, currIndex)
elif xsdTagName == "group":
currIndex = self._checkList (self._checkGroupTag, xsdNode, inputParentNode, inputNodeList, currIndex)
elif xsdTagName == "all":
currIndex = self._checkList (self._checkAllTag, xsdNode, inputParentNode, inputNodeList, currIndex)
elif xsdTagName == "any":
currIndex = self._checkList (self._checkAnyTag, xsdNode, inputParentNode, inputNodeList, currIndex)
elif xsdTagName == "annotation":
# TODO: really nothing to check??
pass
else:
self._addError ("Internal error: Invalid tag %s found!" %repr(xsdTagName))
return currIndex
########################################
# validate attributes of inputNode against complexType node
#
def _checkAttributeTags (self, parentNode, xsdNode, inputNode, validAttrDict):
# retrieve all valid attributes for this element from the schema file
self._updateAttributeDict (xsdNode, validAttrDict)
inputAttrDict = {}
for iAttrName, iAttrValue in inputNode.getAttributeDict().items():
# skip namespace declarations
if iAttrName[0] != XMLNS_NAMESPACE and iAttrName[1] != "xmlns":
inputAttrDict[iAttrName] = iAttrValue
for qAttrName, validAttrEntry in validAttrDict.items():
attrRefNode = validAttrEntry["RefNode"]
# global attributes use always form "qualified"
if self.xsdAttributeDict.has_key(qAttrName) and self.xsdAttributeDict[qAttrName] == attrRefNode:
attributeForm = "qualified"
else:
attributeForm = attrRefNode.getAttributeOrDefault ("form", self._getAttributeFormDefault(xsdNode))
attrRefNode.setAttribute ("form", attributeForm)
self._checkAttributeTag (qAttrName, validAttrEntry["Node"], attrRefNode, inputNode, inputAttrDict)
for inputAttribute in inputAttrDict.keys():
if inputAttribute == (XSI_NAMESPACE, "type"):
pass # for attribute xsi:type refer _checkElementTag
elif inputAttribute == (XSI_NAMESPACE, "nil"):
if parentNode.getAttributeOrDefault ("nillable", "false") == "false":
self._addError ("Tag %s hasn't been defined as nillable!" %repr(inputNode.getTagName()), inputNode)
elif inputNode == self.inputRoot and inputAttribute in ((XSI_NAMESPACE, "noNamespaceSchemaLocation"), (XSI_NAMESPACE, "schemaLocation")):
pass
elif validAttrDict.has_key("__ANY_ATTRIBUTE__"):
xsdNode = validAttrDict["__ANY_ATTRIBUTE__"]["Node"]
try:
inputNamespace = inputAttribute[0]
if inputAttribute[0] == None and xsdNode.getAttribute("form") == "unqualified":
# TODO: Check: If only local namespace is allowed, do not use target namespace???
if xsdNode.getAttribute("namespace") != "##local":
inputNamespace = self._getTargetNamespace(xsdNode)
self._checkWildcardAttribute (xsdNode, inputNode, inputAttribute, inputNamespace, inputAttrDict)
except TagException:
self._addError ("Unexpected attribute %s in Tag %s!" %(repr(inputAttribute), repr(inputNode.getTagName())), inputNode)
else:
self._addError ("Unexpected attribute %s in Tag %s!" %(repr(inputAttribute), repr(inputNode.getTagName())), inputNode)
########################################
# validate one attribute (defined by xsdNode) of inputNode
#
def _checkAttributeTag (self, qAttrName, xsdAttrNode, xsdAttrRefNode, inputNode, inputAttrDict):
targetNamespace = self._getTargetNamespace(xsdAttrNode)
if qAttrName[0] == targetNamespace and xsdAttrRefNode.getAttribute("form") == "unqualified":
qAttrName = NsNameTupleFactory( (None, qAttrName[1]) )
use = xsdAttrNode.getAttribute("use")
if use == None: use = xsdAttrRefNode.getAttributeOrDefault ("use", "optional")
fixedValue = xsdAttrNode.getAttribute("fixed")
if fixedValue == None:
fixedValue = xsdAttrRefNode.getAttribute("fixed")
if inputAttrDict.has_key(qAttrName):
if use == "prohibited":
self._addError ("Attribute %s is prohibited in this context!" %repr(qAttrName[1]), inputNode)
elif inputAttrDict.has_key((targetNamespace, qAttrName[1])):
self._addError ("Local attribute %s must be unqualified!" %(repr(qAttrName)), inputNode)
del inputAttrDict[(targetNamespace, qAttrName[1])]
elif inputAttrDict.has_key((None, qAttrName[1])) and qAttrName[0] == targetNamespace:
self._addError ("Attribute %s must be qualified!" %repr(qAttrName[1]), inputNode)
del inputAttrDict[(None, qAttrName[1])]
else:
if use == "required":
self._addError ("Attribute %s is missing!" %(repr(qAttrName)), inputNode)
elif use == "optional":
if xsdAttrRefNode.hasAttribute("default"):
if not (inputNode.getNsName() == (XSD_NAMESPACE, "element") and
inputNode.hasAttribute("ref") and
xsdAttrRefNode.getAttribute("name") == "nillable"):
defaultValue = xsdAttrRefNode.getAttribute("default")
inputNode.setAttribute(qAttrName, defaultValue)
inputAttrDict[qAttrName] = defaultValue
elif fixedValue != None:
inputNode.setAttribute(qAttrName, fixedValue)
inputAttrDict[qAttrName] = fixedValue
if inputAttrDict.has_key(qAttrName):
attributeValue = inputAttrDict[qAttrName]
self._checkSimpleType (xsdAttrRefNode, "type", inputNode, qAttrName, attributeValue, fixedValue, 1)
del inputAttrDict[qAttrName]
inputNode.setXsdAttrNode(qAttrName, xsdAttrRefNode)
########################################
# update dictionary of valid attributes
#
def _updateAttributeDict (self, xsdNode, validAttrDict, checkForDuplicateAttr=0, recursionKeys=None):
# TODO: Why can recursionKeys not be initialized by default variable??
if recursionKeys == None: recursionKeys = {}
validAttributeNodes = xsdNode.getChildrenNS(self.xsdNsURI, "attribute")
for validAttrGroup in xsdNode.getChildrenNS(self.xsdNsURI, "attributeGroup"):
refNsName = validAttrGroup.getQNameAttribute("ref")
if self.xsdAttrGroupDict.has_key(refNsName):
if recursionKeys.has_key(refNsName):
self._addError ("Circular definition for attribute group %s detected!" %(repr(refNsName)), validAttrGroup)
continue
recursionKeys[refNsName] = 1
self._updateAttributeDict(self.xsdAttrGroupDict[refNsName], validAttrDict, checkForDuplicateAttr, recursionKeys)
for validAttributeNode in validAttributeNodes:
if validAttributeNode.hasAttribute("ref"):
attrKey = validAttributeNode.getQNameAttribute("ref")
attributeRefNode = self.xsdAttributeDict[attrKey]
else:
attrKey = validAttributeNode.getQNameAttribute("name")
attrKey = (self._getTargetNamespace(validAttributeNode), validAttributeNode.getAttribute("name"))
attributeRefNode = validAttributeNode
if checkForDuplicateAttr and validAttrDict.has_key(attrKey):
self._addError ("Duplicate attribute %s found!" %repr(attrKey), validAttributeNode)
else:
validAttrDict[attrKey] = {"Node":validAttributeNode, "RefNode":attributeRefNode}
anyAttributeNode = xsdNode.getFirstChildNS(self.xsdNsURI, "anyAttribute")
if anyAttributeNode != None:
validAttrDict["__ANY_ATTRIBUTE__"] = {"Node":anyAttributeNode, "RefNode":anyAttributeNode}
########################################
# validate wildcard specification of anyElement
#
def _checkWildcardElement (self, xsdNode, inputNode, inputNamespace):
processContents = xsdNode.getAttributeOrDefault("processContents", "lax")
self._checkInputNamespace (xsdNode, inputNode, inputNamespace)
inputNsName = inputNode.getNsName()
if processContents == "skip":
pass
else:
if inputNode.hasAttribute((XSI_NAMESPACE, "type")):
# overloaded type is used
typeNsName = inputNode.getQNameAttribute((XSI_NAMESPACE, "type"))
if not self.xsdTypeDict.has_key(typeNsName):
self._addError ("Unknown overloaded type %s!" %(repr(typeNsName)), inputNode, 0)
else:
typeType = self.xsdTypeDict[typeNsName].getLocalName()
if typeType == "complexType":
try:
self._checkComplexTypeTag (None, self.xsdTypeDict[typeNsName], inputNode, 0)
except TagException, errInst:
self._addError (errInst.errstr, errInst.node, errInst.endTag)
else:
simpleTypeReturnDict = {"BaseTypes":[], "primitiveType":None}
try:
self.simpleTypeVal.checkSimpleType (inputNode, inputNode.getLocalName(), typeNsName, inputNode.getElementValue(), simpleTypeReturnDict, idCheck=1)
except SimpleTypeError, errInst:
self._addError (errInst.args[0], inputNode)
elif self.xsdElementDict.has_key(inputNsName):
self._checkElementTag (self.xsdElementDict[inputNsName], None, (inputNode,), 0)
elif processContents == "strict":
self._addError ("Element definition %s not found in schema file!" %repr(inputNsName), inputNode)
########################################
# validate wildcard specification of anyElement/anyAttribute
#
def _checkWildcardAttribute (self, xsdNode, inputNode, qAttrName, inputNamespace, inputAttrDict):
processContents = xsdNode.getAttributeOrDefault("processContents", "strict")
self._checkInputNamespace (xsdNode, inputNode, inputNamespace)
if processContents == "skip":
pass
elif processContents == "lax":
if self.xsdAttributeDict.has_key(qAttrName):
attrNode = self.xsdAttributeDict[qAttrName]
self._checkAttributeTag (qAttrName, attrNode, attrNode, inputNode, inputAttrDict)
elif processContents == "strict":
if self.xsdAttributeDict.has_key(qAttrName):
attrNode = self.xsdAttributeDict[qAttrName]
self._checkAttributeTag (qAttrName, attrNode, attrNode, inputNode, inputAttrDict)
else:
self._addError ("Attribute definition %s not found in schema file!" %repr(qAttrName), inputNode)
########################################
# validate wildcard specification of anyElement/anyAttribute
#
def _checkInputNamespace (self, xsdNode, inputNode, inputNamespace):
targetNamespace = self._getTargetNamespace(xsdNode)
namespaces = xsdNode.getAttributeOrDefault("namespace", "##any")
if namespaces == "##any":
pass # nothing to check
elif namespaces == "##other":
if inputNamespace == targetNamespace or inputNamespace == None:
raise TagException ("Node or attribute must not be part of target namespace or local!", inputNode)
else:
for namespace in string.split(collapseString(namespaces), " "):
if namespace == "##local" and inputNamespace == None:
break
elif namespace == "##targetNamespace" and inputNamespace == targetNamespace:
break
elif namespace == inputNamespace:
break
else:
raise TagException ("Node or attribute is not part of namespace %s!" %repr(namespaces), inputNode)
########################################
# validate unique and key definition
#
def _checkIdentityConstraint (self, identityConstrNode, inputNode):
identConstrTag = identityConstrNode.getLocalName()
identConstrName = identityConstrNode.getAttribute ("name")
identConstrNsLocalName = (self._getTargetNamespace(identityConstrNode), identConstrName)
selectorXPathNode = identityConstrNode.getFirstChildNS (self.xsdNsURI, "selector")
selectorNodeList, dummy, dummy = self._getXPath (inputNode, selectorXPathNode)
valueDict = {}
for selectorNode in selectorNodeList:
fieldXPathNodeList = identityConstrNode.getChildrenNS (self.xsdNsURI, "field")
keyValue = []
baseTypesList = []
for fieldXPathNode in fieldXPathNodeList:
fieldChildList, attrNodeList, attrName = self._getXPath (selectorNode, fieldXPathNode, identConstrTag)
if len(fieldChildList) > 1:
self._addError ("The field xPath %s of %s %s must evaluate to exactly 0 or 1 node!" %(repr(fieldXPathNode["xpath"]), repr(identConstrTag), repr(identConstrName)), selectorNode)
return
for fieldChild in fieldChildList:
if attrNodeList == []:
inputChild = fieldChild
try:
baseTypes = self._setBaseTypes(fieldChild.getXsdNode())
except:
baseTypes = ((XSD_NAMESPACE, "anyType"),)
value = fieldChild.getElementValue()
else:
inputChild = attrNodeList[0]
try:
baseTypes = self._setBaseTypes(attrNodeList[0].getXsdAttrNode(attrName))
except:
baseTypes = ((XSD_NAMESPACE, "anyType"),)
value = fieldChild
if baseTypes != None:
if baseTypes[0] in ((XSD_NAMESPACE, "anyType"), (XSD_NAMESPACE, "anySimpleType")):
overloadedType = inputChild.getQNameAttribute((XSI_NAMESPACE, "type"))
if overloadedType != (None, None):
baseTypes = [inputChild.getQNameAttribute((XSI_NAMESPACE, "type")),]
else:
self._addError ("Identity constraint does not have a simple type!", inputChild)
continue
baseTypesList.append(baseTypes)
for baseType in baseTypes:
try:
value = self._getOrderedValue (inputChild, attrName, baseType, value)
break
except SimpleTypeError, errInst:
pass
keyValue.append (value)
if keyValue != []:
keyValue = tuple(keyValue)
if not valueDict.has_key (keyValue):
valueDict[keyValue] = 1
self.xsdIdentityConstrDict[identConstrNsLocalName]["ValueDict"][keyValue] = baseTypesList
else:
if len(keyValue) == 1:
self._addError ("Duplicate identity constraint values %s found for identity contraint %s!" %(repr(keyValue[0]), repr(identConstrName)), selectorNode)
else:
self._addError ("Duplicate identity constraint values %s found for identity contraint %s!" %(repr(keyValue), repr(identConstrName)), selectorNode)
########################################
# validate unique and key definition
#
def _checkKeyRefConstraint (self, keyrefNode, inputNode):
keyRefName = keyrefNode.getAttribute ("name")
keyReference = keyrefNode.getQNameAttribute ("refer")
selectorXPathNode = keyrefNode.getFirstChildNS (self.xsdNsURI, "selector")
selectorNodeList, dummy, dummy = self._getXPath (inputNode, selectorXPathNode)
for selectorNode in selectorNodeList:
fieldXPathNodeList = keyrefNode.getChildrenNS(self.xsdNsURI, "field")
keyValue = []
for fieldXPathNode in fieldXPathNodeList:
fieldChildList, attrNodeList, attrName = self._getXPath (selectorNode, fieldXPathNode, "keyref")
if len(fieldChildList) > 1:
self._addError ("The field xPath of keyref %s must evaluate to exactly 0 or 1 node!" %repr(keyRefName), fieldXPathNode)
return
for fieldChild in fieldChildList:
if attrNodeList == []:
inputChild = fieldChild
baseTypes = self._setBaseTypes(fieldChild.getXsdNode())
value = fieldChild.getElementValue()
else:
inputChild = attrNodeList[0]
baseTypes = self._setBaseTypes(attrNodeList[0].getXsdAttrNode(attrName))
value = fieldChild
if baseTypes != None:
for baseType in baseTypes:
try:
value = self._getOrderedValue (inputChild, attrName, baseType, value)
break
except SimpleTypeError, errInst:
pass
keyValue.append (value)
keyValue = tuple(keyValue)
if keyValue != ():
if not self.xsdIdentityConstrDict[keyReference]["ValueDict"].has_key (keyValue):
self._addError ("Key reference value %s is undefined for key type %s!" %(repr(keyValue), repr(keyReference)), selectorNode)
else:
baseTypesList = self.xsdIdentityConstrDict[keyReference]["ValueDict"][keyValue]
for fieldXPathNode, baseTypes in zip(fieldXPathNodeList, baseTypesList):
fieldChildList, attrNodeList, attrName = self._getXPath (selectorNode, fieldXPathNode, "keyref")
if attrNodeList == []:
inputChild = fieldChildList[0]
refBaseTypes = self._setBaseTypes(fieldChildList[0].getXsdNode())
else:
inputChild = attrNodeList[0]
refBaseTypes = self._setBaseTypes(inputChild.getXsdAttrNode(attrName))
if baseTypes[0] not in refBaseTypes and refBaseTypes[0] not in baseTypes:
if baseTypes[0] != (XSD_NAMESPACE, "anyType") and refBaseTypes[0] != (XSD_NAMESPACE, "anyType"):
self._addError ("Key type and key reference type does not match (%s != %s)!" %(repr(baseTypes[0]), repr(refBaseTypes[0])), inputChild)
########################################
# check input element form
#
def _checkInputElementForm (self, xsdNode, xsdNodeNameAttr, inputNode):
targetNamespace = self._getTargetNamespace(xsdNode)
nsNameAttr = (targetNamespace, xsdNodeNameAttr)
if self.xsdElementDict.has_key(nsNameAttr) and self.xsdElementDict[nsNameAttr] == xsdNode:
elementForm = "qualified"
else:
elementForm = xsdNode.getAttributeOrDefault ("form", self._getElementFormDefault(xsdNode))
if elementForm == "qualified":
if inputNode.getNamespaceURI() == None:
if targetNamespace != None:
self._addError ("Element %s must be qualified!" %repr(xsdNodeNameAttr), inputNode)
elif inputNode.getNamespaceURI() != targetNamespace:
self._addError ("%s undefined in specified namespace!" %repr(xsdNodeNameAttr), inputNode)
elif elementForm == "unqualified" and inputNode.getNamespaceURI() != None:
self._addError ("Local element %s must be unqualified!" %repr(xsdNodeNameAttr), inputNode)
########################################
# retrieve ordered value and base types of given typeNsName
#
def _getOrderedValue (self, inputNode, attrName, typeNsName, attrValue):
simpleTypeReturnDict = {"BaseTypes":[], "primitiveType":None}
self.simpleTypeVal.checkSimpleType (inputNode, attrName, typeNsName, attrValue, simpleTypeReturnDict, idCheck=1)
if simpleTypeReturnDict.has_key("orderedValue"):
attrValue = simpleTypeReturnDict["orderedValue"]
return attrValue
########################################
# retrieve nodes/attributes specified by given xPath
#
def _getXPath (self, node, xPathNode, identityConstraint=None):
xPath = xPathNode.getAttribute("xpath")
try:
attrIgnoreList = [(XSI_NAMESPACE, "nil")]
childList, attrNodeList, attrName = node.getXPathList (xPath, namespaceRef=xPathNode, useDefaultNs=0, attrIgnoreList=attrIgnoreList)
except Exception, errInst:
self._addError (errInst.args, node)
childList = []
attrNodeList = []
attrName = None
if childList == []:
if identityConstraint == "key":
self.errorHandler.addError ("Key is missing! XPath = %s!" %repr(xPath), node)
elif identityConstraint in ("unique", "keyref"):
self.errorHandler.addWarning ("Identity constraint is missing! XPath = %s!" %repr(xPath), node)
return childList, attrNodeList, attrName
########################################
# retrieve basetypes from XML attribute (string format)
#
def _setBaseTypes (self, xsdNode):
if xsdNode.getAttribute("BaseTypes") != None:
baseTypes = string.split(xsdNode["BaseTypes"])
baseTypeList = map (lambda basetype: NsNameTupleFactory(basetype), baseTypes)
if baseTypeList != []:
return baseTypeList
else:
return None
else:
return None
########################################
# retrieve target namespace attribute for given node
#
def _getTargetNamespace(self, node):
schemaRootNode = node.getSchemaRootNode()
return schemaRootNode.getAttribute("targetNamespace")
########################################
# retrieve element form default attribute for given node
#
def _getElementFormDefault(self, node):
schemaRootNode = node.getSchemaRootNode()
return schemaRootNode.getAttributeOrDefault("elementFormDefault", "unqualified")
########################################
# retrieve element form default attribute for given node
#
def _getAttributeFormDefault(self, node):
schemaRootNode = node.getSchemaRootNode()
return schemaRootNode.getAttributeOrDefault("attributeFormDefault", "unqualified")
########################################
# define own exception for XML schema validation errors
#
class TagException (StandardError):
def __init__ (self, errstr="", node=None, endTag=0):
self.node = node
self.errstr = errstr
self.endTag = endTag
StandardError.__init__(self)