def validateKeyRefs(elt,krds): res=1 for ref in krds: if ref.refer is None: break candidates=ref.selector.find(elt) if candidates: # print ('c', candidates,candidates[0].localName) if elt.keyTabs.has_key(ref.refer): keyTab=elt.keyTabs[ref.refer] if keyTab=='bogus': break else: elt.keyTabs[ref.refer]='bogus' verror(elt, "No key or unique constraint named %s applies below here, refed by keyref {%s}%s"%(unicode(str(ref.refer.qname),'utf-8'),ref.targetNamespace, unicode(str(ref.name),'utf-8')), ref.schema,"cvc-identity-constraint.2.3.2") break for s in candidates: keyKey=_buildKey(s,ref.fields,ref.schema) # print ('k',keyKey) if not keyKey: continue if len(keyKey)>1: keyKey=tuple(keyKey) else: keyKey=keyKey[0] if not keyTab.has_key(keyKey): verror(s,"no key in %s for %s"%(unicode(str(ref.refer.qname),'utf-8'), unicode(keyKey)), ref.schema, "cvc-identity-constraint.2.3.2")
def validateKeys1(elt,kds,reqd): for key in kds: tab={} candidates=key.selector.find(elt) if candidates: for s in candidates: keyKey=_buildKey(s,key.fields,key.schema) if keyKey is not None: if len(keyKey)>1: keyKey=tuple(keyKey) else: keyKey=keyKey[0] else: if reqd: verror(s, "missing one or more fields %s from key {%s}%s"%(key.fields, key.targetNamespace, unicode(str(key.name),'utf-8')), key.schema,"cvc-identity-constraint.2.2.2") continue if tab.has_key(keyKey): if reqd: code="cvc-identity-constraint.2.2.3" else: code="cvc-identity-constraint.2.1.2" verror(s,"duplicate key %s for {%s}%s, first appearance was %s"% (unicode(keyKey), key.targetNamespace,unicode(str(key.name),'utf-8'), whereString(tab[keyKey].where)), key.schema,code) else: tab[keyKey]=s s.hasKey=1 elt.keyTabs[key]=tab
def checkIDTable(idTable,schema,docElt): for (key,val) in idTable.items(): l=len(val) if l is 0: verror(docElt,"id %s referred to but never declared"%key,schema, "cvc-id.1") elif l is not 1: verror(val[1],"duplicate id %s, first appearance was %s"%(key, whereString(val[0].where)), schema, "cvc-id.2")
def validateElementSimple(element, type, schema, declaration): # check that: # it has no attributes (except xsi: ones) # it has one pcdata child, and if so # the text of the pcdata matches the type if element.attributes: for a in element.attributes.values(): if a.namespaceName != xsi: verror(element, "element {%s}%s with simple type not allowed attributes"% (element.namespaceName, element.localName), schema,"cvc-elt.4.1.1") return # verror(element,"xxx {%s}%s with simple type"%(element.namespaceName, element.localName),schema,"yy") return validateTextModel(element, type, schema, declaration)
def validateTextModel(element, type, schema,declaration=None): # check that: # it has one pcdata child, and if so # the text of the pcdata matches the type name = element.localName text=None bogus=0 if declaration is not None: vc=declaration.valueConstraint else: vc=None for child in element.children: if isinstance(child,XICharacters): if not text: text=child.characters else: text=text+child.characters elif isinstance(child,XIElement): verror(element, "element {%s}%s with simple type not allowed element children"% (element.namespaceName,name),schema,"cvc-complex-type.1.2.2") # TODO: mark this (and any others) as not validated return 1 else: if not text: if vc is not None: if declaration.typeDefinition.simple()!=type: # xsi type was used, need to revalidate vc # TODO: should use canonical form of vcv, not original res=validateText(type,vc[1],element,element) if res is not None: verror(element, "default doesn't satisfy xsi:type: %s%s"%(vc[1],res), schema,"cvc-element.5.1.1") text=vc[1] # TODO: should use canonical form of vcv, not original else: text="" res=validateText(type,text, element, element) if res is not None: verror(element,"element content failed type check: %s%s"%(text,res), schema,"cvc-complex-type.1.2.2") elif (vc and vc[0]=='fixed' and element.actualValue!=declaration.vcv): verror(element,"fixed value did not match: %s!=%s"%(element.schemaNormalizedValue,vc[1]),schema,"cvc-element.5.2.2.2") res=1 if res is not None: try: del element.schemaNormalizedValue except AttributeError: pass try: del element.actualValue except AttributeError: pass return 0
def validateChildTypes(element, schema, lax, idTable): # validate each child element against its type, if we know it # report an error if we don't know it and it's not in <any> v = 1 for child in element.children: if isinstance(child,XIElement): if child.__dict__.has_key('type') and child.type is not None: if child.eltDecl is not None: validateElement(child,child.type,schema,child.eltDecl) else: # child.type is actually a wildcard child.type.validate(child,schema,'element',element) elif lax: # TODO: record impact of missing type in PSVI validateElement(child,None,schema) # will be lax because no type else: verror(child, "undeclared element %s"% unicode(str(QName(None,child.localName,child.namespaceName or None)),'utf-8'), schema,"src-resolve") if ((child.assessedType is not None) and (child.validity=="valid")): td=child.assessedType if td.idt: if td.idt is 3: for ids in child.actualValue: if ids not in idTable: idTable[ids]=[] elif td.idt is 2: if child.actualValue not in idTable: idTable[child.actualValue]=[] elif td.idt is 1: try: idTable[child.actualValue].append(element) except KeyError: idTable[child.actualValue]=[element] if child.idTable: for (key,val) in child.idTable.items(): try: idTable[key].extend(val) except KeyError: idTable[key]=val return idTable
def validateXSIAttrs(element,schema): for a in element.attributes.values(): if a.namespaceName == xsi: if a.localName not in ('type','nil','schemaLocation','noNamespaceSchemaLocation'): verror(element,"unknown xsi attribute %s" % a.localName,schema, "cvc-complex-type.1.3") a.type=None else: a.type=schema.sschema.sforsi.attributeTable[a.localName] res=validateText(a.type.typeDefinition, a.normalizedValue,a,element) a.assessedType = a.type.typeDefinition if res is not None: verror(element, "attribute type check failed for %s: %s%s"%(a.localName, a.normalizedValue, res), schema,'cvc-attribute.1.2',0,None,a) else: a.schemaNormalizedValue=a.normalizedValue a.assess(schema.sschema,a.type)
def _buildKey(s,fps,schema): keyKey=[] for fp in fps: kv=fp.find(s) if kv: # print ('f', kv,kv[0].localName) if len(kv)>1: verror(s,"Field XPath %s produced multiple hits"%fp.str, schema, "cvc-identity-constraint.3") if kv[0].assessedType is None: # has to have been validated OK to be used return if isinstance(kv[0],Element): try: nulla=kv[0].attributes[(xsi,"nil")] if (nulla.validity=='valid' and nulla.schemaNormalizedValue == "true"): # pretend not here -- key will error, others OK -- NOT IN REC!!! return except KeyError: pass try: keyKey.append(_hashable(kv[0].actualValue)) except AttributeError: # TODO: is this really OK, i.e. mixed content? if (len(kv[0].children)>0 and isinstance(kv[0].children[0],Characters)): keyKey.append(kv[0].children[0].characters) else: # XPath says in this case value is the empty string keyKey.append("") elif isinstance(kv[0],Attribute): keyKey.append(_hashable(kv[0].actualValue)) else: # TODO error or shouldnt? vwarn(s,"oops, key value %s:%s"%(type(kv[0]),kv[0]),schema) else: return return keyKey
def assignAttributeTypes(element, attrdefs, extendable, schema, lax): # look up each attribute in attrdefs and assign its type # error if attr declaration is not found and type is not extendable # print "assigning attrs for %s {%s}%s" % (element.originalName, element.namespaceName, element.localName) # print "declared attrs are:" # for zz in attrdefs.keys(): # if isinstance(zz, QName): # print "{%s}%s " % (zz.uri, zz.local) # else: # print zz element.attrTable={} for a in element.attributes.values(): # print "assigning attr %s {%s}%s,%s,%s" % (a.originalName, a.namespaceName, a.localName,lax,attrdefs.has_key("#any")) ansn=a.namespaceName an=QName(None,a.localName,ansn or None) element.attrTable[an]=a if ansn == xsi: continue elif attrdefs.has_key(an): a.type = attrdefs[an] elif lax: if ansn: schema.sschema.tryHardForDecl(a.localName,ansn,'attribute',schema,a) if schema.vAttributeTable.has_key(an): a.type=schema.vAttributeTable[an] else: a.type=None else: a.type=None elif (attrdefs.has_key("#any") and attrdefs["#any"].attributeDeclaration.allows(ansn or None)): a.type = attrdefs["#any"].attributeDeclaration else: verror(element,"undeclared attribute %s" % unicode(str(an),'utf-8'),schema, "cvc-complex-type.1.3") a.type = None return
def validateAttributeTypes(element,attrs, attrdefs, schema): # check that each attribute matches its type # check that all required attributes are present for (adq,ad) in attrdefs.items(): if not attrs.has_key(adq): if ad.minOccurs==1: verror(element,"required attribute %s not present"%unicode(str(adq),'utf-8'),schema, 'cvc-complex-type.1.4') vc=ad.valueConstraint if ((vc is None) and isinstance(ad.attributeDeclaration,Attribute)): vc=ad.attributeDeclaration.valueConstraint if vc is not None: na=XIAttribute(element,adq.uri,adq.local,None, vc[1], # hack, not called for by REC 0) na.actualValue=ad.vcv na.schemaNormalizedValue=vc[1] # should be canon val for actualVal na.assessedType=na.typeDefinition=ad.attributeDeclaration.typeDefinition na.attributeDeclaration=ad.attributeDeclaration na.validity='valid' na.validationAttempted='full' na.validationContext=schema.sschema.docElt element.addAttribute(na) idTable={} xss=schema.sschema.sfors for (an,a) in attrs.items(): if an.uri==xsi: # handled already continue elif a.type is not None: if isinstance(a.type,AttributeUse): ad=a.type.attributeDeclaration td=ad.typeDefinition if a.type.valueConstraint is None: vc=ad.valueConstraint else: vc=a.type.valueConstraint else: ad=a.type if not isinstance(ad,Wildcard): td=ad.typeDefinition vc=ad.valueConstraint else: vc=None if isinstance(ad,Wildcard): res=ad.validate(a,schema,'attribute',element) else: if td is not None: res=validateText(td,a.normalizedValue,a,element) if res is None: a.assessedType = td if td.idt: if td.idt is 3: for ids in a.actualValue: idTable[ids]=[] elif td.idt is 2: idTable[a.actualValue]=[] elif td.idt is 1: idTable[a.actualValue]=[element] if (vc is not None) and vc[0]=='fixed': if a.actualValue!=a.type.vcv: verror(element,"fixed value did not match for attribute %s: %s!=%s"%(unicode(str(an),'utf-8'), a.normalizedValue,vc[1]),schema,"cvc-attribute.1.3") else: res=None if res is not None: verror(element,"attribute type check failed for %s: %s%s"%(unicode(str(an),'utf-8'), a.normalizedValue, res), schema,'cvc-attribute.1.2',0,None,a) a.schemaNormalizedValue=None else: ad=None a.assess(schema.sschema,ad) return idTable
def av(self,child,schema,kind,elt): q = QName(None,child.localName,child.namespaceName or None) if kind=='element': kinde='child' else: kinde=kind vwarn(elt,"allowing %s as %s because it matched wildcard(%s)" % (unicode(str(q),'utf-8'),kinde,self.allowed),schema) if self.processContents!='skip': # print "looking for decl for %s" % child.originalName schema.sschema.tryHardForDecl(child.localName, child.namespaceName,kind,schema,child) if schema.sschema.schemas.has_key(child.namespaceName): try: if kind=='element': e = schema.vElementTable[q] else: e = schema.vAttributeTable[q] except KeyError: e=None # print "decl for %s is %s" % (child.originalName, e) if (e is not None) and (e.typeDefinition is not None): vwarn(None,"validating it against %s" % unicode(str(e.typeDefinition.name or 'anonymous type'),'utf-8'), schema) if kind=='element': validateElement(child, e.typeDefinition, schema, e) return else: child.assessedType = e.typeDefinition res=validateText(e.typeDefinition,child.normalizedValue, child, elt) # TODO: check child.vc for fixed if res is not None: verror(elt, "attribute type check failed for %s: %s%s"%(unicode(str(q),'utf-8'), child.normalizedValue, res), schema,'cvc-attribute.1.2',0,None,child) child.schemaNormalizedValue=None return elif (self.processContents=='strict' and not (kind=='element' and child.attributes.has_key((xsi, "type")))): # TODO check this against actual def'n of missing component losing=1 elif kind=='element': losing=0 else: # lax attribute, I think return else: schema.sschema.losingNamespaces[child.namespaceName]=1 if self.processContents=='strict': losing=1 else: losing=0 if losing: verror(elt, "can't find a type for wildcard-matching %s %s" %(kinde, unicode(str(q),'utf-8')), schema, "src-resolve") if kind=='element': vwarn(None,"validating it %sly"%self.processContents,schema) validateElement(child,None,schema,0)
def validateElement(element, type, schema, eltDecl=None): sschema=schema.sschema element.idTable=None if eltDecl is None and type is None: # note if we come from a wildcard that's already failed to find a decl, # we don't try again, because eltDecl is 0 in that case nsn=element.namespaceName eqn=QName(None,element.localName,nsn or None) sschema.tryHardForDecl(element.localName,nsn, 'element',schema,element) if schema.vElementTable.has_key(eqn): eltDecl=schema.vElementTable[eqn] if eltDecl is not None: type=eltDecl.typeDefinition if eltDecl==0: eltDecl=None validateXSIAttrs(element,schema) if isinstance(eltDecl,Element): # TODO: is this right if no eltDecl -- think so -- need erratum?? nullable = eltDecl.nullable else: nullable = 1 nulled = 0 if sschema.checkingSchema and element.localName=='import': if element.attributes.has_key((None,"namespace")): ins=element.attributes[(None,"namespace")].normalizedValue else: ins=None sschema.allowedNamespaces.append(ins) if element.attributes.has_key((xsi, "nil")): if not nullable: verror(element, "xsi:nil specified on non-nillable element %s" % element.originalName, schema,"cvc-elt.1.1") element.assess(sschema,eltDecl) return nulla=element.attributes[(xsi,"nil")] nulled = (nulla.validity=='valid' and nulla.schemaNormalizedValue == "true") if element.attributes.has_key((xsi, "type")): xsitype=None typea=element.attributes[(xsi, "type")] if typea.validity=='valid': t = typea.schemaNormalizedValue; (tp,tl) = splitQName(t) # because the attribute, a QName, is valid, the prefix, even # if it's None, must be bound if element.inScopeNamespaces.has_key(tp): qt = QName(tp, tl, element.inScopeNamespaces[tp].namespaceName) else: qt= QName(tp,tl,None) if schema.vTypeTable.has_key(qt): xsitype=schema.vTypeTable[qt] if type is not None and not xsitype.isSubtype(type,type.final): verror(element, "xsi:type %s is not a subtype of the declared type %s"%(unicode(str(qt),'utf-8'), unicode(str(type.name),'utf-8')), schema,"cvc-elt.2.3") elif type is not None: vwarn(element, "using xsi:type %s instead of original %s" % (unicode(str(qt),'utf-8'), unicode(str(type.name),'utf-8')), schema) else: verror(element,"xsi:type %s undefined" % unicode(str(qt),'utf-8'),schema,"cvc-elt.2.2") else: qt=typea.normalizedValue if xsitype is None: if type is None: vwarn(element,"xsi:type %s didn't yield a type" % unicode(str(qt),'utf-8'),schema) else: vwarn(element, "xsi:type %s didn't yield a type, using original %s" % (unicode(str(qt),'utf-8'), unicode(str(type.name),'utf-8')), schema) else: # TODO: enforce {disallowed substitutions} type = xsitype element.assessedType = type element.lax = lax = type is None # might have none in case of recursive call inside <any/>, or at top level, # or after errors if nulled: validateElementNull(element, type, schema) if type is not None: # TODO: check element is not abstract if ((type is not Type.urType) and (isinstance(type, AbInitio) or isinstance(type, SimpleType))): if not nulled: validateElementSimple(element, type, schema, eltDecl) if isinstance(eltDecl,Element): validateKeys(eltDecl,element) element.assess(sschema,eltDecl) return # a complexType if type.abstract=='true': verror(element,"attempt to use abstract type %s to validate"%unicode(str(type.name),'utf-8'), schema,'cvc-complex-type.1') element.assess(sschema,eltDecl) return ad=type.attributeDeclarations ps=type.prohibitedSubstitutions else: ps=[] ad={} assignAttributeTypes(element, ad, ps, schema, lax) idTable=validateAttributeTypes(element, element.attrTable, ad, schema) # print "assigning types for %s" % element.originalName if not nulled: # we must look at the content model before checking the types, so that # we know which children matched <any> if type is not None: noSubTypes=validateContentModel(element, type, schema, eltDecl) idTable=validateChildTypes(element, schema, lax or noSubTypes, idTable) if isinstance(eltDecl,Element): validateKeys(eltDecl,element) element.idTable=idTable if sschema.docElt==element: checkIDTable(idTable,schema,element) element.assess(schema.sschema,eltDecl)
def validateElementModel(element, fsm, mixed, schema, declaration): # print "validating element model for %s" % element.originalName if fsm is None: return fsm.initCounters() n = fsm.startNode #sys.stdout.write("|%s"%n.id) text = None qname = None for c in element.children: if isinstance(c,XICharacters): if mixed: if not text: text=c.characters else: text=text+c.characters elif not _whitespace.match(c.characters): verror(element, "text not allowed: |%s|" % c.characters, schema,"cvc-complex-type.1.2.3") return 1 elif isinstance(c,XIElement): l=n.edges i=len(l)-1 while i>=0: e=l[i] m = e.match(c) if m is not None: # success n = m #sys.stdout.write("-%s->%s"%(unicode(e),m.id)) if e.__class__ is IncrEdge: l=m.edges i=len(l)-1 continue if e.decl is not None: if isinstance(e.decl, Wildcard): c.type = e.decl c.eltDecl=None # not used so don't leave around c.strict = (e.decl.processContents == 'strict') else: c.strict = 1 c.eltDecl=e.decl c.type = c.eltDecl.typeDefinition else: c.strict = 1 c.type = None break i=i-1 else: allowed=[] c.type=None for e in n.edges: eq=unicode(str(e),'utf-8') if eq!="L": allowed.append(eq) fx=fsm.asXML() verror(c, "element %s not allowed here (%s) in element %s, expecting [%s]:\n"% (unicode(str(QName(None, c.localName, c.namespaceName or None)),'utf-8'), n.id, unicode(str(QName(None,element.localName,element.namespaceName or None)),'utf-8'), ",".join(allowed)), schema,"cvc-complex-type.1.2.4",0,fx,element) return 1 l=n.edges i=len(l)-1 # Must go backwards, to get ++ edges first #sys.stdout.write("$$") while i>=0: e=l[i] x=e.matchEnd() if x is None: #sys.stdout.write("N") i=i-1 continue if x.__class__ is FSMNode: n=x #sys.stdout.write("-%s->%s"%(unicode(e),x.id)) l=x.edges i=len(l)-1 continue if x==True: #sys.stdout.write("-%s->|\n"%unicode(e)) break if x==False: #sys.stdout.write("F") i=i-1 continue #sys.stdout.write("e") verror(element,x.errmsg,schema,"cvc-complex-type.1.2.4") i=i-1 else: allowed=[] for e in n.edges: eq=unicode(str(e),'utf-8') if eq!="L": allowed.append(eq) fx=fsm.asXML() verror(element, "content of %s is not allowed to end here (%s), expecting %s:\n"% (element.originalName,n.id,allowed), schema,"cvc-complex-type.1.2.4",1,fx) if declaration is not None: vc=declaration.valueConstraint else: vc=None if vc is not None: if qname: # there were element children if vc[0]=='fixed': verror(element, "element content not allowed with 'fixed' value constraint'", schema,"cvc-element.5.2.2.1") else: # empty or only text if text is None: element.schemaNormalizedValue=element.actualValue=vc[1] else: # content if vc[0]=='fixed': if text==vc[1]: element.schemaNormalizedValue=element.actualValue=vc[1] else: verror(element, "fixed value did not match: %s!=%s"%(text,vc[1]), schema,"cvc-element.5.2.2.2") return 0
def validateEmptyModel(element, type, schema): if len(element.children) != 0: verror(element,"element %s must be empty but is not" % element.originalName,schema, "cvc-complex-type.1.2") return 1 return 0
def validateElementNull(element, type, schema): if len(element.children) != 0: verror(element,"element %s is nilled but is not empty" % element.originalName, schema,"cvc-elt.1.2.1") else: element.null=1