Annotation of xmlschema/applyschema.py, revision 1.89
1.44 ht 1: # Copyright (C) 2000 LTG -- See accompanying COPYRIGHT and COPYING files
1.24 ht 2: # actually apply a schema to an instance
1.89 ! ht 3: # $Id: applyschema.py,v 1.88 2001/03/17 12:11:13 ht Exp $
1.24 ht 4:
1.63 ht 5: from PyLTXML import *
1.83 ht 6: import XML
7: import XMLInfoset
8: import LTXMLInfoset
9: import PSVInfoset
1.58 ht 10: import os
1.41 ht 11: import XMLSchema
1.28 ht 12: import layer
1.3 aqw 13: import sys
1.4 richard 14: import re
1.20 ht 15: import types
1.41 ht 16: import string
1.53 ht 17: from urlparse import urljoin
1.58 ht 18: import tempfile
1.62 ht 19: import traceback
1.83 ht 20: import asInfoset
1.81 ht 21: import time
1.4 richard 22:
23: whitespace = re.compile("^[ \t\r\n]*$")
1.83 ht 24: xsi = XMLSchema.XMLSchemaInstanceNS
1.89 ! ht 25: vsraw="$Revision: 1.88 $ of $Date: 2001/03/17 12:11:13 $"
1.40 ht 26: vss=string.split(vsraw)
1.41 ht 27: vs="XSV %s/%s of %s %s"%(string.split(XMLSchema.versionString)[0],
1.40 ht 28: vss[1],vss[5],vss[6])
1.79 ht 29: dontWarn=1
1.5 richard 30:
1.2 ht 31: def readXML(url):
1.67 ht 32: if url:
1.83 ht 33: doc = LTXMLInfoset.documentFromURI(url)
1.67 ht 34: else:
1.83 ht 35: file = FOpen(sys.stdin,
36: NSL_read+NSL_read_all_bits+NSL_read_namespaces+
37: NSL_read_no_consume_prolog)
38: doc = LTXMLInfoset.documentFromFile(file)
39: Close(file)
40: return doc
1.2 ht 41:
1.55 ht 42: def validate(element, typedef, schema, eltDecl):
1.58 ht 43: if not hasattr(schema.factory,'errors'):
44: schema.factory.errors=0
1.55 ht 45: validateElement(element, typedef, schema, eltDecl)
1.33 ht 46: return schema.factory.errors
1.2 ht 47:
1.55 ht 48: def validateElement(element, type, schema, eltDecl=None):
1.4 richard 49: global vel, vtype
50: vel = element
51: vtype = type
1.47 richard 52: if not eltDecl:
1.83 ht 53: eqn=XMLSchema.QName(None,element.localName,element.namespaceName or None)
1.47 richard 54: if s.vElementTable.has_key(eqn):
55: eltDecl=s.vElementTable[eqn]
1.83 ht 56: if eltDecl:
57: type=eltDecl.typeDefinition
58: validateXSIAttrs(element,schema)
1.58 ht 59: nullable = eltDecl and eltDecl.nullable # TODO: is this right if no eltDecl?
1.48 richard 60: nulled = 0
1.88 ht 61: if element.attributes.has_key((xsi, "nil")):
1.48 richard 62: if not nullable:
1.58 ht 63: verror(element,
1.88 ht 64: "xsi:nil specified on non-nillable element %s" % element.originalName,
1.58 ht 65: schema,"cvc-elt.1.1")
1.83 ht 66: element.assess(schema.factory,eltDecl)
1.48 richard 67: return
1.88 ht 68: nulla=element.attributes[(xsi,"nil")]
1.83 ht 69: nulled = (nulla.validity=='valid' and
70: nulla.schemaNormalizedValue == "true")
1.74 richard 71: if element.attributes.has_key((xsi, "type")):
1.83 ht 72: typea=element.attributes[(xsi, "type")]
73: if typea.validity=='valid':
74: t = typea.schemaNormalizedValue;
75: (tp,tl) = XMLSchema.splitQName(t)
76: tp=tp or ''
1.86 ht 77: if element.inScopeNamespaces.has_key(tp):
78: qt = XMLSchema.QName(tp, tl, element.inScopeNamespaces[tp].namespaceName)
1.88 ht 79: elif tp!='':
80: verror (element,
81: "no inscope namespace declaration for prefix of xsi:type %s"%t,
82: schema,"src-qname")
1.86 ht 83: else:
1.88 ht 84: qt= XMLSchema.QName(tp,tl,None)
1.83 ht 85: if schema.vTypeTable.has_key(qt):
86: xsitype=schema.vTypeTable[qt]
87: else:
88: verror(element,"xsi:type %s undefined" % qt,schema,"cvc-elt.2.2")
89: element.assess(schema.factory,eltDecl)
90: return
91: if type and not xsitype.isSubtype(type):
92: verror(element,
1.58 ht 93: "xsi:type %s is not a subtype of the declared type %s"%(qt,
94: type.name),
1.83 ht 95: schema,"cvc-elt.2.3")
96: element.assess(schema.factory,eltDecl)
97: return
98: if type:
99: vwarn(element,
100: "using xsi:type %s instead of original %s" % (qt, type.name))
101: else:
102: vwarn(element,"using xsi:type %s" % qt)
103: type = xsitype
104: element.assessedType = type
1.55 ht 105: lax = not type
106: # might have none in case of recursive call inside <any/>, or at top level
1.48 richard 107: if nulled:
1.83 ht 108: validateElementNull(element, type, schema)
1.55 ht 109: if type:
1.88 ht 110: # TODO: check element is not abstract
1.58 ht 111: if ((not type==XMLSchema.urType) and
112: (isinstance(type, XMLSchema.AbInitio) or
113: isinstance(type, XMLSchema.SimpleType))):
1.83 ht 114: if not nulled:
115: validateElementSimple(element, type, schema)
1.58 ht 116: if eltDecl:
117: validateKeys(eltDecl,element)
1.83 ht 118: element.assess(schema.factory,eltDecl)
1.58 ht 119: return
120: # a complexType
1.88 ht 121: if type.abstract=='true':
122: verror(element,"attempt to use abstract type %s to validate"%type.name,
123: schema,'cvc-complex-type.1')
124: element.assess(schema.factory,eltDecl)
125: return
1.55 ht 126: ad=type.attributeDeclarations
127: ps=type.prohibitedSubstitutions
128: et=type.elementTable
129: else:
130: ps=[]
131: ad={}
132: et={}
133: assignAttributeTypes(element, ad, ps, schema, lax)
134: validateAttributeTypes(element, element.attrTable, ad, schema)
1.83 ht 135: # print "assigning types for %s" % element.originalName
136: if not nulled:
137: assignChildTypes(element.chunkedChildren, et, ps, schema, lax)
138: # we must look at the content model before checking the types, so that
139: # we know which children matched <any>
140: if type:
141: validateContentModel(element, type, schema)
142: validateChildTypes(element.chunkedChildren, schema, lax)
1.21 ht 143: if eltDecl:
1.33 ht 144: validateKeys(eltDecl,element)
1.83 ht 145: element.assess(schema.factory,eltDecl)
146:
1.48 richard 147: def validateElementNull(element, type, schema):
1.74 richard 148: if len(element.chunkedChildren) != 0:
1.88 ht 149: verror(element,"element %s is nilled but is not empty" % element.originalName,
1.58 ht 150: schema,"cvc-elt.1.2.1")
1.83 ht 151: else:
152: element.null=1
1.58 ht 153: # TODO: should check for fixed value constraint
1.48 richard 154:
1.2 ht 155: def validateElementSimple(element, type, schema):
156: # check that:
1.47 richard 157: # it has no attributes (except xsi: ones)
1.2 ht 158: # it has one pcdata child, and if so
159: # the text of the pcdata matches the type
1.74 richard 160: if element.attributes:
161: for a in element.attributes.values():
162: if a.namespaceName != xsi:
1.58 ht 163: verror(element,
164: "element {%s}%s with simple type not allowed attributes"%
1.74 richard 165: (element.namespaceName, element.localName),
1.58 ht 166: schema,"cvc-elt.4.1.1")
1.47 richard 167: return
1.2 ht 168: return validateTextModel(element, type, schema)
169:
1.83 ht 170: def validateXSIAttrs(element,schema):
171: for a in element.attributes.values():
172: if a.namespaceName == xsi:
1.88 ht 173: if a.localName not in ('type','nil','schemaLocation','noNamespaceSchemaLocation'):
1.83 ht 174: verror(element,"unknown xsi attribute %s" % a.localName,schema,
175: "cvc-complex-type.1.3")
176: else:
177: a.type=schema.factory.sforsi.attributeTable[a.localName]
178: res=a.type.typeDefinition.validateText(a.normalizedValue,a,
179: element,schema)
180: a.assessedType = a.type.typeDefinition
181: if res:
182: verror(element,
183: "attribute type check failed for %s: %s%s"%(a.localName,
184: a.normalizedValue,
185: res),
186: schema,'cvc-attribute.1.2',0,None,a)
187: else:
188: a.schemaNormalizedValue=a.normalizedValue
189: a.assess(schema.factory,a.type)
190:
1.55 ht 191: def assignAttributeTypes(element, attrdefs, extendable, schema, lax):
1.2 ht 192: # look up each attribute in attrdefs and assign its type
193: # error if attr declaration is not found and type is not extendable
1.74 richard 194: # print "assigning attrs for %s {%s}%s" % (element.originalName, element.namespaceName, element.localName)
1.83 ht 195: # print "declared attrs are:"
196: # for zz in attrdefs.keys():
197: # if isinstance(zz, XMLSchema.QName):
198: # print "{%s}%s " % (zz.uri, zz.local)
199: # else:
200: # print zz
1.33 ht 201: element.attrTable={}
1.74 richard 202: for a in element.attributes.values():
1.83 ht 203: # print "assigning attr %s {%s}%s,%s,%s" % (a.originalName, a.namespaceName, a.localName,lax,attrdefs.has_key("#any"))
204: an=XMLSchema.QName(None,a.localName,a.namespaceName or None)
1.33 ht 205: element.attrTable[an]=a
1.74 richard 206: if a.namespaceName == xsi:
1.83 ht 207: continue
1.27 richard 208: elif attrdefs.has_key(an):
1.88 ht 209: a.type = attrdefs[an]
1.55 ht 210: elif lax:
1.74 richard 211: if a.namespaceName and schema.vAttributeTable.has_key(an):
1.55 ht 212: a.type=schema.vAttributeTable[an]
213: else:
214: a.type=None
1.43 ht 215: elif (attrdefs.has_key("#any") and
1.83 ht 216: attrdefs["#any"].attributeDeclaration.allows(a.namespaceName or None)):
1.43 ht 217: a.type = attrdefs["#any"].attributeDeclaration
1.2 ht 218: else:
1.58 ht 219: verror(element,"undeclared attribute %s" % an,schema,
220: "cvc-complex-type.1.3")
1.2 ht 221: a.type = None
1.33 ht 222: return
1.2 ht 223:
1.33 ht 224: def validateAttributeTypes(element,attrs, attrdefs, schema):
1.2 ht 225: # check that each attribute matches its type
226: # check that all required attributes are present
1.88 ht 227: # TODO: add defaulted/fixed attributes (shouldn't need to check their types)
1.33 ht 228: for (adq,ad) in attrdefs.items():
1.88 ht 229: if not attrs.has_key(adq):
230: if ad.minOccurs==1:
231: verror(element,"required attribute %s not present"%adq,schema,
232: 'cvc-complex-type.1.4')
233: vc=ad.valueConstraint
234: if not vc and isinstance(ad.attributeDeclaration,XMLSchema.Attribute):
235: vc=ad.attributeDeclaration.valueConstraint
236: if vc:
237: na=XMLInfoset.Attribute(element,adq.uri,adq.local,
238: vc[1],
239: vc[1],
240: 0)
241: element.addAttribute(na)
1.33 ht 242: for (an,a) in attrs.items():
1.83 ht 243: if an.uri==xsi:
244: # handled already
245: continue
246: elif a.type:
1.88 ht 247: if isinstance(a.type,XMLSchema.AttributeUse):
248: ad=a.type.attributeDeclaration
249: td=ad.typeDefinition
250: vc=a.type.valueConstraint or ad.valueConstraint
1.43 ht 251: else:
1.88 ht 252: ad=a.type
253: if not isinstance(ad,XMLSchema.Wildcard):
254: td=ad.typeDefinition
255: vc=ad.valueConstraint
256: if isinstance(ad,XMLSchema.Wildcard):
257: res=ad.validate(a,schema,'attribute',element)
258: else:
259: if td:
260: res=td.validateText(a.normalizedValue,a,element, schema)
261: a.assessedType = td
262: if vc and vc[0]=='fixed':
263: if a.normalizedValue!=vc[1]:
264: verror(element,"fixed value did not match for attribute %s: %s!=%s"%(an,a.normalizedValue,vc[1]),schema,"cvc-attribute.1.3")
1.58 ht 265: else:
266: res=None
1.33 ht 267: if res:
268: verror(element,"attribute type check failed for %s: %s%s"%(an,
1.74 richard 269: a.normalizedValue,
1.33 ht 270: res),
1.83 ht 271: schema,'cvc-attribute.1.2',0,None,a)
272: a.schemaNormalizedValue=None
1.88 ht 273: else:
274: ad=None
275: a.assess(schema.factory,ad)
1.2 ht 276:
1.55 ht 277: def assignChildTypes(children, elementTable, extendable, schema, lax):
1.2 ht 278: # look up each child tag and record the type
279: # (it may not be an error if it is not declared; we don't know that
280: # until we see what it matches in the content model)
1.88 ht 281: # TODO: extendable
1.2 ht 282: for child in children:
1.83 ht 283: if isinstance(child,XMLInfoset.Element):
284: qname = XMLSchema.QName(None,child.localName,child.namespaceName or None)
1.10 richard 285: if elementTable.has_key(qname):
1.82 ht 286: decl=elementTable[qname]
1.83 ht 287: child.type = decl.typeDefinition
1.82 ht 288: child.eltDecl = decl
1.74 richard 289: elif lax and child.namespaceName and schema.vElementTable.has_key(qname):
1.82 ht 290: decl=schema.vElementTable[qname]
291: child.type=decl.typeDefinition
292: child.eltDecl=decl
1.2 ht 293: else:
294: child.type = None
1.82 ht 295: child.eltDecl=None
1.2 ht 296: return 1
297:
298: def validateContentModel(element, type, schema):
299: # trace a path through the content model
300: # if a child matches an <any tag=... type=...> we need to indicate
301: # that that child should be validated with its xsd:type if it has one
302: # if a child matches some other kind of <any> we need to indicate
303: # that it's not an error if we can't find its type
304:
1.83 ht 305: # print "validating model for %s content type %s" % (element.originalName, type.contentType)
1.33 ht 306: if type.contentType == "empty":
307: validateEmptyModel(element, type, schema)
308: elif type.contentType == "textOnly":
309: validateTextModel(element, type.model, schema)
310: else:
311: validateElementModel(element, type.fsm,
312: type.contentType == "mixed", schema)
1.2 ht 313:
314: def validateEmptyModel(element, type, schema):
1.74 richard 315: if len(element.chunkedChildren) != 0:
316: verror(element,"element %s must be empty but is not" % element.originalName,schema,
1.58 ht 317: "cvc-complex-type.1.2")
1.2 ht 318:
319: def validateTextModel(element, type, schema):
320: # check that:
321: # it has one pcdata child, and if so
322: # the text of the pcdata matches the type
1.83 ht 323: name = element.localName
1.58 ht 324: n=0
1.74 richard 325: for child in element.chunkedChildren:
1.83 ht 326: if isinstance(child,XMLInfoset.Characters):
1.58 ht 327: n=1
1.83 ht 328: elif isinstance(child,XMLInfoset.Element):
1.58 ht 329: verror(element,
330: "element {%s}%s with simple type not allowed element children"%
1.74 richard 331: (element.namespaceName,name),schema,"cvc-complex-type.1.2.2")
1.66 ht 332: # TODO: mark this (and any others) as not validated
1.62 ht 333: return
1.2 ht 334: else:
335: if n == 0:
336: text = ""
337: else:
1.74 richard 338: text = element.chunkedChildren[0].characters
1.83 ht 339: res=type.validateText(text, element, element, schema)
1.33 ht 340: if res:
341: verror(element,"element content failed type check: %s%s"%(text,res),
1.58 ht 342: schema,"cvc-complex-type.1.2.2")
1.83 ht 343: element.schemaNormalizedValue=None
1.2 ht 344:
1.4 richard 345: def validateElementModel(element, fsm, mixed, schema):
1.74 richard 346: # print "validating element model for %s" % element.originalName
1.4 richard 347: n = fsm.startNode
1.74 richard 348: for c in element.chunkedChildren:
1.83 ht 349: if isinstance(c,XMLInfoset.Characters):
1.74 richard 350: if (not mixed) and (not whitespace.match(c.characters)):
1.83 ht 351: verror(element,
352: "text not allowed: |%s|" % c.characters,
1.58 ht 353: schema,"cvc-complex-type.1.2.3")
1.33 ht 354: return
1.83 ht 355: elif isinstance(c,XMLInfoset.Element):
356: qname = XMLSchema.QName(None, c.localName, c.namespaceName or None)
1.8 richard 357: next = None
1.13 richard 358: anynext = None
1.4 richard 359: for e in n.edges:
1.10 richard 360: if e.label == qname:
1.8 richard 361: next = e.dest
1.83 ht 362: c.strict = 1
1.4 richard 363: break
1.43 ht 364: if isinstance(e.label, XMLSchema.Wildcard):
1.83 ht 365: if e.label.allows(c.namespaceName or None):
1.41 ht 366: anynext = e.dest
367: anylab = e.label
1.8 richard 368: if not next:
1.13 richard 369: if anynext:
370: n = anynext
1.83 ht 371: c.strict = (anylab.processContents == 'strict')
1.17 richard 372: # this is no longer an error, but something more complicated is XXX
373: # if c.type:
374: # where(child.where)
375: # print "element matched <any> but had a type assigned"
376: # v = 0
377: # else:
378: # c.type = "<any>"
1.33 ht 379: c.type = anylab
1.13 richard 380: else:
1.83 ht 381: allowed=[]
382: for e in n.edges:
383: if isinstance(e.label, XMLSchema.QName):
384: allowed.append(str(e.label))
385: elif isinstance(e.label, XMLSchema.Wildcard):
386: allowed.append("{%s}:*"%str(e.label.allowed))
387: fx=fsm.asXML()
1.58 ht 388: verror(c,
1.83 ht 389: "element %s not allowed here (%s) in element %s, expecting %s:\n"%
390: (qname, n.id,
391: XMLSchema.QName(None,element.localName,element.namespaceName or None),
392: allowed),
393: schema,"cvc-complex-type.1.2.4",0,fx)
1.13 richard 394: else:
395: n = next
1.4 richard 396: if not n.isEndNode:
1.83 ht 397: allowed=[]
398: for e in n.edges:
399: if isinstance(e.label, XMLSchema.QName):
400: allowed.append(str(e.label))
401: elif isinstance(e.label, XMLSchema.Wildcard):
402: allowed.append(e.label.allowed)
403: fx=fsm.asXML()
1.58 ht 404: verror(element,
1.83 ht 405: "content of %s is not allowed to end here (%s), expecting %s:\n"%
406: (element.originalName,n.id,allowed),
407: schema,"cvc-complex-type.1.2.4",1,fx)
1.33 ht 408: return
1.2 ht 409:
1.55 ht 410: def validateChildTypes(children, schema, lax):
1.2 ht 411: # validate each child element against its type, if we know it
412: # report an error if we don't know it and it's not in <any>
1.7 richard 413: v = 1
1.2 ht 414: for child in children:
1.83 ht 415: if isinstance(child,XMLInfoset.Element):
1.33 ht 416: if child.type:
1.82 ht 417: if child.eltDecl:
418: validateElement(child,child.type,schema,child.eltDecl)
419: else:
420: # child.type is actually a wildcard
421: child.type.validate(child,schema,'element',child)
1.55 ht 422: elif lax:
1.82 ht 423: # TODO: check that this branch ever happens at all
1.58 ht 424: # TODO: record impact of missing type in PSVI
1.55 ht 425: validateElement(child,None,schema) # will be lax because no type
1.2 ht 426: else:
1.33 ht 427: verror(child,
1.58 ht 428: "undeclared element %s"%
1.83 ht 429: XMLSchema.QName(None,child.localName,child.namespaceName or None),
1.58 ht 430: schema,"src-resolve")
1.2 ht 431:
1.21 ht 432: def validateKeys(decl,elt):
1.22 ht 433: elt.keyTabs={}
1.33 ht 434: validateKeys1(elt,decl.keys,1)
435: validateKeys1(elt,decl.uniques,0)
436: validateKeyRefs(elt,decl.keyrefs)
1.22 ht 437:
438: def validateKeys1(elt,kds,reqd):
1.88 ht 439: # TODO: propagate upwards
1.22 ht 440: for key in kds:
1.21 ht 441: tab={}
1.84 ht 442: candidates=key.selector.find(elt)
1.21 ht 443: if candidates:
444: for s in candidates:
1.84 ht 445: keyKey=buildKey(s,key.fields)
1.59 ht 446: if keyKey:
447: if len(keyKey)>1:
448: keyKey=tuple(keyKey)
449: else:
450: keyKey=keyKey[0]
451: else:
452: if reqd:
453: verror(s,
1.69 ht 454: "missing one or more fields %s from key %s"%(key.fields,
1.59 ht 455: key.name),
456: key.schema,"cvc-identity-constraint.2.2.2")
1.87 richard 457: continue
1.21 ht 458: if tab.has_key(keyKey):
1.58 ht 459: if reqd:
460: code="cvc-identity-constraint.2.2.3"
461: else:
462: code="cvc-identity-constraint.2.1.2"
463: verror(s,"duplicate key %s, first appearance was %s"%
464: (str(keyKey),
465: XMLSchema.whereString(tab[keyKey].where)),
466: key.schema,code)
1.21 ht 467: else:
468: tab[keyKey]=s
1.22 ht 469: elt.keyTabs[key.name]=tab
470:
471: def buildKey(s,fps):
472: keyKey=[]
473: for fp in fps:
1.24 ht 474: kv=fp.find(s)
1.22 ht 475: if kv:
476: if len(kv)>1:
1.58 ht 477: # TODO error or shouldnt?
1.33 ht 478: vwarn(s,"oops, multiple field hits for %s at %s: %s"%(fp.str,s,kv))
1.83 ht 479: if isinstance(kv[0],XMLInfoset.Element):
1.74 richard 480: if (len(kv[0].chunkedChildren)>0 and
1.83 ht 481: isinstance(kv[0].chunkedChildren[0],XMLInfoset.Characters)):
1.74 richard 482: keyKey.append(kv[0].chunkedChildren[0].characters)
1.22 ht 483: else:
484: # XPath says in this case value is the empty string
485: pass
1.83 ht 486: elif XML.somestring(type(kv[0])):
1.22 ht 487: keyKey.append(kv[0])
488: else:
1.58 ht 489: # TODO error or shouldnt?
1.33 ht 490: vwarn(s,"oops, key value %s:%s"%(type(kv[0]),kv[0]))
1.22 ht 491: else:
1.83 ht 492: return
1.22 ht 493: return keyKey
494:
495: def validateKeyRefs(elt,krds):
496: res=1
497: for ref in krds:
1.25 ht 498: if elt.keyTabs.has_key(ref.refer):
499: keyTab=elt.keyTabs[ref.refer]
500: if keyTab=='bogus':
501: break
502: else:
503: elt.keyTabs[ref.refer]='bogus'
1.52 richard 504: verror(elt,
1.33 ht 505: "No key or unique constraint named %s declared, refed by keyref %s"%(ref.refer,ref.name),
1.58 ht 506: ref.schema,"cvc-identity-constraint.2.3.2")
1.25 ht 507: break
1.84 ht 508: candidates=ref.selector.find(elt)
1.22 ht 509: if candidates:
510: for s in candidates:
1.84 ht 511: keyKey=buildKey(s,ref.fields)
1.22 ht 512: if not keyKey:
1.87 richard 513: continue
1.22 ht 514: if len(keyKey)>1:
515: keyKey=tuple(keyKey)
516: else:
517: keyKey=keyKey[0]
1.25 ht 518: if not keyTab.has_key(keyKey):
1.58 ht 519: verror(s,"no key in %s for %s"%(ref.refer,str(keyKey)),ref.schema,
520: "cvc-identity-constraint.2.3.2")
1.21 ht 521:
1.58 ht 522: def findSchemaLocs(element,schema):
1.30 richard 523: pairs = []
1.74 richard 524: for a in element.attributes.values():
525: if a.namespaceName == xsi:
526: if a.localName == "schemaLocation":
527: scls=string.split(a.normalizedValue)
1.43 ht 528: while scls:
1.58 ht 529: if len(scls)>1:
530: pairs.append((scls[0], scls[1]))
531: else:
1.74 richard 532: verror(element,"xsi:schemaLocation must be a list with an even number of members: %s"%string.split(a.normalizedValue),schema,"???")
1.43 ht 533: scls=scls[2:]
1.74 richard 534: elif a.localName == "noNamespaceSchemaLocation":
535: pairs.append((None,a.normalizedValue))
536: for c in element.chunkedChildren:
1.83 ht 537: if isinstance(c, XMLInfoset.Element):
1.58 ht 538: scl=findSchemaLocs(c,schema)
1.43 ht 539: if scl:
540: pairs = pairs + scl
1.30 richard 541: return pairs
542:
1.81 ht 543: def runitAndShow(en,rns=[],k=0,style=None,enInfo=None,outfile=None,dw=1,
1.89 ! ht 544: timing=0,reflect=0,independent=0):
1.79 ht 545: global dontWarn
546: dontWarn=dw
1.81 ht 547: if timing:
548: timing=time.time()
1.89 ! ht 549: (res,encoding,errs)=runit(en,rns,k,timing,independent)
1.81 ht 550: if timing:
551: sys.stderr.write("Finished: %6.2f\n"%(time.time()-timing))
1.58 ht 552: if not encoding:
553: encoding='UTF-8'
1.75 ht 554: if outfile:
555: try:
556: outf=open(outfile,"w")
557: except:
558: sys.stderr.write("couldn't open %s for output, falling back to stderr"%
559: outfile)
560: outf=sys.stderr
561: else:
562: outf=sys.stderr
563: errout=OpenStream(outf,
1.58 ht 564: CharacterEncodingNames[encoding],
565: NSL_write+NSL_write_plain)
566: if encoding!='UTF-8':
567: es=" encoding='%s'"%encoding
568: else:
569: es=""
1.75 ht 570: PrintTextLiteral(errout,"<?xml version='1.0'%s?>\n"%es)
1.58 ht 571: if style:
1.75 ht 572: PrintTextLiteral(errout,
573: "<?xml-stylesheet type='text/xsl' href='%s'?>\n"%style)
1.64 ht 574: if enInfo:
575: for (k,v) in enInfo.items():
576: res.addAttr(k,v)
1.78 ht 577: if errs:
1.76 ht 578: res.addAttr("crash","true")
1.58 ht 579: res.printme(errout)
1.75 ht 580: PrintTextLiteral(errout,"\n")
1.58 ht 581: Close(errout)
1.88 ht 582: if reflect and not errs:
1.83 ht 583: dumpInfoset(sys.stdout)
1.78 ht 584: if errs:
585: return string.join(map(lambda es:string.join(es,''),errs),'')
1.76 ht 586: else:
587: return
588:
589: class SchemaValidationError(Exception):
590: def __init__(self,arg):
591: Exception.__init__(self,arg)
1.58 ht 592:
1.89 ! ht 593: def runit(en,rns=[],k=0,timing=0,independent=0):
1.78 ht 594: global s,e,t,f,res,ed,btlist
1.89 ! ht 595: if independent:
! 596: rns[0:0]=[en]
1.78 ht 597: btlist=[]
1.33 ht 598:
1.45 ht 599: ss = s = None
1.33 ht 600:
1.41 ht 601: f=XMLSchema.newFactory()
1.58 ht 602: f.errors=0
1.36 ht 603: base=f.fileNames[0]
1.67 ht 604: if en:
605: ren=urljoin(base,en)
606: else:
607: ren=None
1.30 richard 608:
1.83 ht 609: res=XML.Element("xsv")
1.58 ht 610: f.resElt=res
611: res.addAttr("xmlns","http://www.w3.org/2000/05/xsv")
612: res.addAttr("version",vs)
1.89 ! ht 613: if independent:
! 614: res.addAttr("target","[standalone schema assessment]")
! 615: else:
! 616: res.addAttr("target",ren or "[stdin]")
! 617:
1.58 ht 618: if rns:
619: res.addAttr("schemaDocs",string.join(rns,' '))
620:
621: rdn=tempfile.mktemp("xsverrs")
622: redirect=open(rdn,"w+")
623: savedstderr=os.dup(2) # save stderr
624: os.dup2(redirect.fileno(),2)
1.89 ! ht 625: if independent:
1.58 ht 626: e=None
1.89 ! ht 627: encoding="UTF-8"
! 628: else:
! 629: try:
! 630: doc=readXML(ren)
! 631: e=doc.documentElement
! 632: f.docElt=e
! 633: encoding=doc.documentEntity.charset
! 634: if timing:
! 635: os.write(savedstderr,"target read: %6.2f\n"%(time.time()-timing))
! 636: except:
! 637: pfe=XML.Element("bug")
! 638: pfe.children=[XML.Pcdata("validator crash during target reading")]
! 639: res.children.append(pfe)
! 640: e=None
! 641: encoding=None
! 642: if not e:
! 643: res.addAttr('instanceAssessed',"false")
! 644: sys.stderr.flush()
! 645: registerRawErrors(redirect,res)
! 646: # put stderr back
! 647: os.dup2(savedstderr,2)
! 648: return (res,None,btlist)
1.58 ht 649:
650: # TODO: check each schema doc against schema for schemas, if possible,
651: # unless caller explicitly opts out (?)
1.28 ht 652: if rns:
1.49 ht 653: try:
1.53 ht 654: s = XMLSchema.fromFile(urljoin(base,rns[0]),f)
1.81 ht 655: if timing:
656: os.write(savedstderr,"schema read: %6.2f\n"%(time.time()-timing))
1.78 ht 657: except:
1.83 ht 658: pfe=XML.Element("bug")
659: pfe.children=[XML.Pcdata("validator crash during schema reading")]
1.78 ht 660: res.children.append(pfe)
661: btlist.append(traceback.format_exception(sys.exc_type,
662: sys.exc_value,
663: sys.exc_traceback))
1.30 richard 664: for rn in rns[1:]:
1.49 ht 665: try:
1.67 ht 666: ffr=XMLSchema.fromFile(urljoin(base,rn),f)
1.81 ht 667: if timing:
668: os.write(savedstderr,"schema read: %6.2f\n"%(time.time()-timing))
1.67 ht 669: ss=ss or ffr
1.78 ht 670: except:
1.83 ht 671: pfe=XML.Element("bug")
672: pfe.children=[XML.Pcdata("validator crash during schema reading")]
1.78 ht 673: res.children.append(pfe)
674: btlist.append(traceback.format_exception(sys.exc_type,
675: sys.exc_value,
676: sys.exc_traceback))
1.30 richard 677:
1.45 ht 678: if not s:
1.65 ht 679: if ss:
680: s=ss
681: else:
682: s = XMLSchema.Schema(f,None)
683: s.targetNS='##dummy'
1.45 ht 684:
1.89 ! ht 685: if not independent:
! 686: schemaLocs = findSchemaLocs(e,s)
! 687: res.addAttr('schemaLocs',string.join(map(lambda p:"%s -> %s"%(p[0] or 'None',p[1]),
! 688: schemaLocs),
! 689: '; '))
! 690: for (ns, sl) in schemaLocs:
! 691: try:
! 692: XMLSchema.checkinSchema(f, ns, sl,e,ren or "[stdin]")
! 693: if timing:
! 694: os.write(savedstderr,"schema read: %6.2f\n"%(time.time()-timing))
! 695: except:
! 696: pfe=XML.Element("bug")
! 697: pfe.children=[XML.Pcdata("validator crash during schema reading")]
! 698: res.children.append(pfe)
! 699: btlist.append(traceback.format_exception(sys.exc_type,
! 700: sys.exc_value,
! 701: sys.exc_traceback))
! 702:
! 703: res.addAttr('docElt',"{%s}%s"%(e.namespaceName,e.localName))
! 704: if (e.namespaceName and
! 705: (e.namespaceName not in ('http://www.w3.org/XML/1998/namespace',xsi)) and
! 706: not f.schemas.has_key(e.namespaceName)):
! 707: try:
! 708: XMLSchema.checkinSchema(f,e.namespaceName,e.namespaceName,e,ren or "[stdin]")
! 709: if timing:
! 710: os.write(savedstderr,"schema read: %6.2f\n"%(time.time()-timing))
! 711: res.addAttr('nsURIDeref','success')
! 712: except:
! 713: pfe=XML.Element("bug")
! 714: pfe.children=[XML.Pcdata("validator crash during schema reading")]
! 715: res.children.append(pfe)
! 716: btlist.append(traceback.format_exception(sys.exc_type,
! 717: sys.exc_value,
! 718: sys.exc_traceback))
! 719: res.addAttr('nsURIDeref','failure')
1.30 richard 720:
1.58 ht 721: sys.stderr.flush()
722: registerRawErrors(redirect,res)
723: # put stderr back
724: os.dup2(savedstderr,2)
725:
726: try:
727: ecount=XMLSchema.prepare(f)
1.81 ht 728: if timing:
1.89 ! ht 729: sys.stderr.write("factory prepared: %6.2f\n"%(time.time()-timing))
! 730: if independent:
! 731: for ss in f.schemas.values():
! 732: ss.prepare()
! 733: if timing:
! 734: sys.stderr.write("schemas prepared: %6.2f\n"%(time.time()-timing))
1.58 ht 735: except:
736: ecount=-1
1.78 ht 737: btlist.append(traceback.format_exception(sys.exc_type,
738: sys.exc_value,
739: sys.exc_traceback))
1.83 ht 740: pfe=XML.Element("bug")
741: pfe.children=[XML.Pcdata("validator crash during factory preparation")]
1.58 ht 742: res.children.append(pfe)
1.76 ht 743:
1.89 ! ht 744: if independent:
! 745: kgm="false"
! 746: kg=0
! 747: else:
! 748: kgm="true"
! 749: kg=1
1.33 ht 750: if ecount:
1.58 ht 751: if ecount<0:
752: kg=0
1.33 ht 753: else:
1.58 ht 754: if not k:
755: kg=0
756: if not kg:
757: kgm="false"
758: res.addAttr('instanceAssessed',kgm)
759: if not kg:
1.89 ! ht 760: if independent or ecount<0:
! 761: if ecount<0:
! 762: ecount=0
1.82 ht 763: for sch in f.schemas.values():
764: ecount=ecount+sch.errors
765: res.addAttr('schemaErrors',str(ecount))
1.78 ht 766: return (res,encoding,btlist)
1.30 richard 767:
1.74 richard 768: cl=string.find(':',e.originalName)
1.28 ht 769: if cl>-1:
1.74 richard 770: prefix=e.originalName[0:cl]
1.28 ht 771: else:
772: prefix=''
1.83 ht 773: eltname = XMLSchema.QName(prefix,e.localName,e.namespaceName or None)
1.30 richard 774:
775: if not s:
776: # any one will do
1.33 ht 777: s = f.sfors
778: t=None
779:
1.55 ht 780: ed=None
1.33 ht 781: if s and s.vElementTable.has_key(eltname):
1.55 ht 782: ed=s.vElementTable[eltname]
783: t=ed.typeDefinition
1.58 ht 784: if t:
785: if t.name:
1.66 ht 786: if hasattr(t,'qname'):
787: tn=t.qname.string()
788: else:
789: tn=t.name
1.58 ht 790: else:
791: tn='[Anonymous]'
792: res.addAttr('rootType',tn)
793: res.addAttr('validation','strict')
794: else:
795: res.addAttr('validation','lax')
1.33 ht 796:
797: if e and s:
1.76 ht 798: try:
799: validate(e, t, s, ed)
1.83 ht 800: sforsi=PSVInfoset.NamespaceSchemaInformation(f.schemas[XMLSchema.XMLSchemaNS])
801: sforsi.schemaComponents.sort(PSVInfoset.compareSFSComps) # ensure atomics
802: # are first
803: e.schemaInformation=[sforsi,
804: PSVInfoset.NamespaceSchemaInformation(f.schemas[xsi])]
805: for s in f.schemas.values():
806: if s.targetNS not in (XMLSchema.XMLSchemaNS,xsi):
807: e.schemaInformation.append(PSVInfoset.NamespaceSchemaInformation(s))
1.76 ht 808: except:
1.78 ht 809: btlist.append(traceback.format_exception(sys.exc_type,
810: sys.exc_value,
811: sys.exc_traceback))
1.83 ht 812: pfe=XML.Element("bug")
813: pfe.children=[XML.Pcdata("validator crash during validation")]
1.76 ht 814: res.children.append(pfe)
1.58 ht 815: res.addAttr('instanceErrors',str(s.factory.errors))
1.77 ht 816: ec=0
817: for sch in f.schemas.values():
818: ec=ec+sch.errors
819: res.addAttr('schemaErrors',str(ec))
1.78 ht 820: return (res,encoding,btlist)
1.30 richard 821:
1.58 ht 822: def registerRawErrors(redirect,res):
823: if redirect.tell():
824: redirect.seek(0)
1.83 ht 825: ro=XML.Element("XMLMessages")
1.58 ht 826: o="\n%s"%redirect.read()
1.83 ht 827: ro.children=[XML.Pcdata(o)]
1.58 ht 828: res.children.append(ro)
829: redirect.close()
830:
1.83 ht 831: def verror(elt,message,schema,code=None,two=0,daughter=None,iitem=None):
1.58 ht 832: # code argument identifies CVC
1.83 ht 833: ve=XML.Element("invalid")
834: ve.children=[XML.Pcdata(message)]
1.58 ht 835: if code:
836: ve.addAttr("code",code)
1.33 ht 837: if two:
1.58 ht 838: XMLSchema.where(ve,elt.where2)
1.33 ht 839: else:
1.58 ht 840: XMLSchema.where(ve,elt.where)
841: if daughter:
842: ve.children.append(daughter)
843: res.children.append(ve)
1.33 ht 844: schema.factory.errors=schema.factory.errors+1
1.83 ht 845: if not iitem:
846: iitem=elt
847: if iitem.errorCode:
848: iitem.errorCode.append(" "+code)
849: else:
850: iitem.errorCode=[code]
1.33 ht 851:
852: def vwarn(elt,message):
1.79 ht 853: if dontWarn:
854: return
1.83 ht 855: ve=XML.Element("warning")
856: ve.children=[XML.Pcdata(message)]
1.33 ht 857: if elt:
1.58 ht 858: XMLSchema.where(ve,elt.where)
859: res.children.append(ve)
1.24 ht 860:
1.41 ht 861: # validation methods for schema components
862:
1.43 ht 863: def av(self,child,schema,kind,elt):
1.83 ht 864: q = XMLSchema.QName(None,child.localName,child.namespaceName or None)
1.43 ht 865: vwarn(elt,"allowing %s because it matched wildcard(%s)" %
866: (q,self.allowed))
867: if self.processContents!='skip':
1.83 ht 868: # print "looking for decl for %s" % child.originalName
1.74 richard 869: if schema.factory.schemas.has_key(child.namespaceName):
1.41 ht 870: # only try if we might win -- needs work
871: try:
1.43 ht 872: if kind=='element':
873: e = schema.vElementTable[q]
874: else:
875: e = schema.vAttributeTable[q]
1.41 ht 876: except KeyError:
877: e=None
1.83 ht 878: # print "decl for %s is %s" % (child.originalName, e)
1.58 ht 879: if e and e.typeDefinition:
1.43 ht 880: vwarn(None,"validating it against %s" %
881: (e.typeDefinition.name or 'anonymous type'))
882: if kind=='element':
883: validateElement(child, e.typeDefinition, schema)
884: else:
1.83 ht 885: child.assessedType = e.typeDefinition
886: res=e.typeDefinition.validateText(child.normalizedValue,child,
887: elt, schema)
888: if res:
889: verror(elt,
890: "attribute type check failed for %s: %s%s"%(q,
891: child.normalizedValue,
892: res),
893: schema,'cvc-attribute.1.2',0,None,child)
894: child.schemaNormalizedValue=None
1.61 ht 895: elif (self.processContents=='strict' and
1.74 richard 896: not (kind=='element' and child.attributes.has_key((xsi, "type")))):
1.58 ht 897: # TODO check this against actual def'n of missing component
1.43 ht 898: verror(elt,
899: "can't find a type for wildcard-matching %s %s" %(kind, q),
1.58 ht 900: schema,
901: "src-resolve")
1.61 ht 902: elif kind=='element':
903: vwarn(None,"validating it laxly")
904: validateElement(child,None,schema)
1.83 ht 905:
1.43 ht 906: XMLSchema.Wildcard.validate=av
1.42 ht 907:
1.43 ht 908: def tv(self,child,schema,kind,elt):
1.42 ht 909: validateElement(child, self, schema)
1.41 ht 910:
1.43 ht 911: XMLSchema.Type.validate=XMLSchema.AbInitio.validate=tv
1.41 ht 912:
1.83 ht 913: def validateText(self, text, item, context, schema):
1.58 ht 914: if self==XMLSchema.urType:
915: return
916: else:
1.69 ht 917: if self.variety=='atomic':
918: # ref may have failed
1.83 ht 919: if self.primitiveType:
920: return self.primitiveType.checkString(self.primitiveType.normalize(text,
921: item),
922: context)
923: else:
924: item.schemaNormalizedValue=None
925: return
1.69 ht 926: elif self.variety=='list':
927: it=self.itemType
1.58 ht 928: # TODO: what about post-list facets?
1.70 ht 929: if not it:
930: return
1.83 ht 931: for substr in string.split(normalize(None,text,item,'collapse')):
932: res=it.validateText(substr,None,context,schema)
1.58 ht 933: if res:
934: return res+' in list'
935: return
1.69 ht 936: elif self.variety=='union':
937: mts=self.memberTypes
938: subres=[]
939: # TODO: what about post-union facets?
940: for mt in mts:
1.70 ht 941: if mt:
1.83 ht 942: res=mt.validateText(text,item,context,schema)
1.70 ht 943: if res:
944: subres.append(res)
945: else:
946: # bingo
947: return
1.69 ht 948: # no subtypes won, we lose
1.83 ht 949: item.schemaNormalizedValue=None
1.70 ht 950: return " no members of union succeeded: %s"%subres
1.58 ht 951: else:
1.69 ht 952: XMLSchema.shouldnt('vv '+str(self.variety))
1.58 ht 953:
954: XMLSchema.SimpleType.validateText=validateText
955:
1.83 ht 956: def validateText(self, text, item, context, schema):
957: return self.checkString(self.normalize(text,item),context)
1.58 ht 958:
959: XMLSchema.AbInitio.validateText=validateText
960:
1.71 richard 961: # checkString methods
962:
963: def checkString(self,str,context):
1.83 ht 964: if self.facetValue('enumeration')!=None:
965: evs=self.facetValue('enumeration')
966: for val in evs:
1.71 richard 967: if val==str:
968: return
1.83 ht 969: return " not in enumeration %s"%evs
1.71 richard 970:
971: XMLSchema.AbInitio.checkString = checkString
972:
1.83 ht 973: wsoChar=re.compile("[\t\r\n]")
974: wsChars=re.compile("[ \t\r\n]+")
975: iSpace=re.compile("^ ")
976: fSpace=re.compile(" $")
977: def normalize(self,str,item,ws=None):
978: if not item:
979: # list component, shouldn't be processed
980: return str
981: if not ws:
982: ws=self.facetValue('whiteSpace')
983: if ws=='replace':
984: str=wsoChar.sub(' ',str)
985: elif ws=='collapse':
986: str=wsChars.sub(' ',str)
987: str=iSpace.sub('',str)
988: str=fSpace.sub('',str)
989: # else ((not ws) or ws=='preserve'): pass
990: item.schemaNormalizedValue=str
991: return str
992:
993: XMLSchema.AbInitio.normalize=normalize
994:
1.71 richard 995: def checkString(self,str,context):
996: try:
997: if ('.' in str) or ('E' in str):
998: val=string.atof(str)
999: else:
1000: val=string.atoi(str)
1001: except ValueError:
1002: return " does not represent a number"
1.83 ht 1003: minI=self.facetValue('minInclusive')
1004: if minI!=None and val<minI:
1005: return "<%d"%minI
1006: minE=self.facetValue('minExclusive')
1007: if minE!=None and val<=minE:
1008: return "<=%d"%minE
1009: maxI=self.facetValue('maxInclusive')
1010: if maxI!=None and val>maxI:
1011: return ">%d"%maxI
1012: maxE=self.facetValue('maxExclusive')
1013: if maxE!=None and val>=maxE:
1014: return ">=%d"%maxE
1.72 richard 1015: return XMLSchema.AbInitio.checkString(self,str,context)
1.71 richard 1016:
1017: XMLSchema.DecimalST.checkString = checkString
1018:
1019: def checkString(self,str,context):
1020: # not complete by any means
1021: parts=string.split(str,':')
1022: if len(parts)>2:
1023: return " has more than one colon"
1.83 ht 1024: if len(parts)==2 and not context.inScopeNamespaces.has_key(parts[0]):
1.71 richard 1025: return " has undeclared prefix: %s"%parts[0]
1.72 richard 1026: return XMLSchema.AbInitio.checkString(self,str,context)
1.71 richard 1027:
1028: XMLSchema.QNameST.checkString = checkString
1.58 ht 1029:
1.83 ht 1030: # assess methods
1031:
1032: def assess(self,factory,decl):
1033: allfull = 1
1034: allnone = 1
1035: nochildren = 1
1036: for c in self.chunkedChildren:
1037: if isinstance(c, XMLInfoset.Element):
1038: nochildren = 0
1039: validationAttempted = c.__dict__.has_key("validationAttempted") and c.validationAttempted
1040: if validationAttempted != 'full':
1041: allfull = 0
1042: if validationAttempted and c.validationAttempted != 'none':
1043: allnone = 0
1044: attrs=self.attributes.values()
1045: for c in attrs:
1046: if isinstance(c, XMLInfoset.Attribute):
1047: nochildren = 0
1048: validationAttempted = c.__dict__.has_key("validationAttempted") and c.validationAttempted
1049: if validationAttempted != 'full':
1050: allfull = 0
1051: if validationAttempted and c.validationAttempted != 'none':
1052: allnone = 0
1053:
1054: if nochildren:
1055: if self.assessedType:
1056: self.validationAttempted = 'full'
1057: else:
1058: self.validationAttempted = 'none'
1059: else:
1060: if allfull and self.assessedType:
1061: self.validationAttempted = 'full'
1062: elif allnone and not self.assessedType:
1063: self.validationAttempted = 'none'
1064: else:
1065: self.validationAttempted = 'partial'
1066:
1067: if self.errorCode:
1068: self.validity = 'invalid'
1069: else:
1070: has_losing_child = 0
1071: has_untyped_strict_child = 0
1072: has_non_winning_typed_child = 0
1073: for c in self.chunkedChildren:
1074: if not isinstance(c, XMLInfoset.Element):
1075: continue
1076: strict = c.__dict__.has_key("strict") and c.strict
1.88 ht 1077: validatedType = c.__dict__.has_key("assessedType") and c.assessedType
1.83 ht 1078: validity = c.__dict__.has_key("validity") and c.validity
1079: if validity == 'invalid':
1080: has_losing_child = 1
1081: if strict and not validatedType:
1082: has_untyped_strict_child = 1
1083: if validatedType and validity != 'valid':
1084: has_non_winning_typed_child = 1
1085: for c in attrs:
1086: if not isinstance(c, XMLInfoset.Attribute):
1087: continue
1088: strict = c.__dict__.has_key("strict") and c.strict
1.88 ht 1089: validatedType = c.__dict__.has_key("assessedType") and c.assessedType
1.83 ht 1090: validity = c.__dict__.has_key("validity") and c.validity
1091: if validity == 'invalid':
1092: has_losing_child = 1
1093: if strict and not validatedType:
1094: has_untyped_strict_child = 1
1095: if validatedType and validity != 'valid':
1096: has_non_winning_typed_child = 1
1097: if has_losing_child or has_untyped_strict_child:
1098: self.validity = 'invalid'
1099: elif has_non_winning_typed_child:
1100: self.validity = 'unknown'
1101: else:
1102: self.validity = 'valid'
1103:
1104: if self.assessedType and self.validity=='valid':
1105: self.typeDefinition=self.assessedType
1106: self.elementDeclaration=decl
1107: self.validationContext=factory.docElt
1108:
1109: XMLInfoset.Element.assess=assess
1110: XMLInfoset.Element.assessedType=None
1111:
1112: def assess(self,factory,decl):
1113: if self.errorCode:
1114: self.validity = 'invalid'
1115: else:
1116: self.validity = 'valid'
1117: if self.assessedType:
1118: self.validationAttempted = 'full'
1119: if self.validity=='valid':
1120: self.typeDefinition=self.assessedType
1121: self.attributeDeclaration=decl
1122: else:
1123: self.validationAttempted = 'none'
1124: self.validity = 'unknown'
1125: self.validationContext=factory.docElt
1126:
1127: XMLInfoset.Attribute.assess=assess
1128: XMLInfoset.Attribute.assessedType=None
1129:
1130: def dumpInfoset(fileOrName):
1131: close=0
1132: if type(fileOrName)==types.FileType:
1133: ff=fileOrName
1134: else:
1135: close=1
1136: ff = open(fileOrName, "w")
1137: r = f.docElt.parent.reflect()
1138: r.documentElement.inScopeNamespaces["psv"]=XMLInfoset.Namespace("psv",
1139: PSVInfoset.infosetSchemaNamespace)
1140: r.indent("",1)
1141: r.printme(ff)
1142: if close:
1143: ff.close()
1144:
1.42 ht 1145: # run at import if top
1146:
1147: if __name__=='__main__':
1148: argl=sys.argv[1:]
1149: k=0
1.79 ht 1150: dw=1
1.81 ht 1151: timing=0
1.58 ht 1152: style=None
1.75 ht 1153: outfile=None
1.83 ht 1154: reflect=0
1.89 ! ht 1155: independent=0
1.83 ht 1156: proFile=None
1.42 ht 1157: while argl:
1158: if argl[0]=='-k':
1159: k=1
1.58 ht 1160: elif argl[0]=='-s':
1161: style=argl[1]
1162: argl=argl[1:]
1.75 ht 1163: elif argl[0]=='-o':
1164: outfile=argl[1]
1165: argl=argl[1:]
1.83 ht 1166: elif argl[0]=='-p':
1167: proFile=argl[1]
1168: argl=argl[1:]
1.79 ht 1169: elif argl[0]=='-w':
1170: dw=0
1.81 ht 1171: elif argl[0]=='-t':
1172: timing=1
1.83 ht 1173: elif argl[0]=='-r':
1174: reflect=1
1.89 ! ht 1175: elif argl[0]=='-i':
! 1176: independent=1
1.75 ht 1177: elif argl[0][0]=='-':
1.89 ! ht 1178: sys.stderr.write("Usage: [-ktwri] [-s stylesheet] [-o outputFile] [-p profileOut] file [schema1 schema2 . . .]\n")
1.75 ht 1179: sys.exit(-1)
1.42 ht 1180: else:
1181: break
1182: argl=argl[1:]
1183:
1184: if argl:
1.83 ht 1185: if proFile:
1186: import profile
1187: res=profile.run("""runitAndShow(argl[0],argl[1:],k,
1.89 ! ht 1188: style,None,outfile,dw,timing,reflect,independent)""",
1.83 ht 1189: proFile)
1190: else:
1.89 ! ht 1191: res=runitAndShow(argl[0],argl[1:],
! 1192: k,style,None,outfile,dw,timing,reflect,independent)
1.42 ht 1193: else:
1.89 ! ht 1194: res=runitAndShow(None,[],k,
! 1195: style,None,outfile,dw,timing,reflect,independent)
1.76 ht 1196:
1197: if res:
1198: raise SchemaValidationError,res
1.41 ht 1199:
1.25 ht 1200: # $Log: applyschema.py,v $
1.89 ! ht 1201: # Revision 1.88 2001/03/17 12:11:13 ht
! 1202: # merge v2001 back in to main line
! 1203: #
1.88 ht 1204: # Revision 1.87 2001/02/16 16:38:43 richard
1205: # fix key/keyref/unique field code
1206: #
1.87 richard 1207: # Revision 1.86 2001/02/12 11:34:46 ht
1208: # catch unbound prefix in xsi:type
1.88 ht 1209: #
1210: # Revision 1.85.2.5 2001/03/15 11:37:59 ht
1211: # check for and rule out use of abstract types
1212: #
1213: # Revision 1.85.2.4 2001/02/24 23:47:56 ht
1214: # handle unbound prefix in xsi:type
1215: # fix typo in assess
1216: #
1217: # Revision 1.85.2.3 2001/02/17 23:33:11 ht
1218: # assignAttrTypes sets a.type to the use if there is one
1219: # so either valueConstraint can be used
1220: #
1221: # Revision 1.85.2.2 2001/02/14 17:01:11 ht
1222: # merge attr use back in to v2001 line
1223: #
1224: # Revision 1.85.2.1.2.1 2001/02/07 17:34:28 ht
1225: # use AttrUse to supply defaults
1226: #
1227: # Revision 1.85.2.1 2001/02/07 14:30:01 ht
1228: # change NS to 2001, implement null->nil
1.87 richard 1229: #
1.86 ht 1230: # Revision 1.85 2001/02/07 09:23:24 ht
1231: # report low-level failure correctly
1232: #
1.85 ht 1233: # Revision 1.84 2001/02/06 14:20:41 ht
1234: # accommodate to earlier XPath construction for fields/selector
1235: #
1.84 ht 1236: # Revision 1.83 2001/02/06 11:30:51 ht
1237: # merged infoset-based back to mainline
1238: #
1.83 ht 1239: # Revision 1.74.2.26 2001/01/15 14:18:55 ht
1240: # improve wildcard error msg
1241: #
1242: # Revision 1.74.2.25 2001/01/03 19:13:19 ht
1243: # accommodate to change of exception with LTXMLInfoset
1244: #
1245: # Revision 1.74.2.24 2001/01/03 11:57:52 ht
1246: # fix xsi:type bugs
1247: #
1248: # Revision 1.74.2.23 2000/12/23 13:08:21 ht
1249: # fix spelling of whiteSpace,
1250: # add -p file switch for profiling
1251: #
1252: # Revision 1.74.2.22 2000/12/22 18:33:54 ht
1253: # add whitespace processing,
1254: # fix some bugs?
1255: #
1256: # Revision 1.74.2.21 2000/12/21 18:29:38 ht
1257: # accommodate to .facets and real facets
1258: #
1259: # Revision 1.74.2.20 2000/12/16 12:10:29 ht
1260: # add logging of relevant declaration to elt/attr assess
1261: #
1262: # Revision 1.74.2.19 2000/12/14 14:21:59 ht
1263: # fix bug in e-o error msg
1264: #
1265: # Revision 1.74.2.18 2000/12/13 23:30:09 ht
1266: # add -r switch to produce reflected output
1267: #
1268: # Revision 1.74.2.17 2000/12/12 17:33:06 ht
1269: # get builtin-schemas out first, sort AbInitios to the front,
1270: # more details in content-model error messages,
1271: # set null property
1272: #
1273: # Revision 1.74.2.16 2000/12/08 18:08:42 ht
1274: # install schemaInformation on validation root,
1275: # assign type defn as such to typeDefinition property
1276: #
1277: # Revision 1.74.2.15 2000/12/08 15:16:07 ht
1278: # put the docElt in the factory,
1279: # use it for reflection at the end,
1280: # and to implement validationContext
1281: #
1282: # Revision 1.74.2.14 2000/12/07 13:18:42 ht
1283: # work around null vs "" for missing namespace name
1284: #
1285: # Revision 1.74.2.13 2000/12/07 10:20:48 ht
1286: # handle xsi: attrs cleanly
1287: #
1288: # Revision 1.74.2.12 2000/12/06 22:43:11 ht
1289: # make assess a method on Element,
1290: # add one on Attribute,
1291: # refer to the latter from the former
1292: #
1293: # Revision 1.74.2.11 2000/12/06 09:21:05 ht
1294: # add psv infoset namespace URI to reflected docapplyschema.py
1295: #
1296: # Revision 1.74.2.10 2000/12/04 22:31:03 ht
1297: # stubs for schemaNormalizedValue in place
1298: #
1299: # Revision 1.74.2.9 2000/12/04 22:09:00 ht
1300: # remove convert,
1301: # accommodate change to importing XML,
1302: # put attribute verror on right item
1303: #
1304: # Revision 1.74.2.8 2000/12/04 13:30:42 ht
1305: # merge in main line fixes thru 1.82
1306: #
1307: # Revision 1.74.2.7 2000/10/13 12:48:42 richard
1308: # more infoset contributions
1309: #
1310: # Revision 1.74.2.6 2000/10/02 13:33:28 richard
1311: # update values for validity property
1312: #
1313: # Revision 1.74.2.5 2000/09/29 17:18:09 richard
1314: # More towards PSV infoset
1315: #
1316: # Revision 1.74.2.4 2000/09/29 16:45:27 richard
1317: # correct errorCode setting
1318: #
1319: # Revision 1.74.2.3 2000/09/29 16:04:24 richard
1320: # More towards PSV infoset
1321: #
1322: # Revision 1.74.2.2 2000/09/29 14:16:15 ht
1323: # towards PSVI contributions
1324: #
1325: # Revision 1.74.2.1 2000/09/27 17:21:20 richard
1326: # Changes for infoset-based
1327: #
1328: # Revision 1.77 2000/09/28 15:54:50 ht
1329: # schema error count includes all errors, not just those found at prep
1330: # time
1331: #
1332: # Revision 1.76 2000/09/28 15:09:14 ht
1333: # try catching and returning any crashes
1334: #
1335: # Revision 1.75 2000/09/28 08:41:57 ht
1336: # add usage message
1337: # add -o outfile cmd line arg
1338: #
1339: # Revision 1.82 2000/10/31 16:30:47 ht
1340: # validate subordinate elements with eltdecl if available
1341: # return schema error count if not attempting instance validation
1342: #
1.82 ht 1343: # Revision 1.81 2000/10/27 15:33:30 ht
1344: # Output timing info if -t on command line
1345: #
1.81 ht 1346: # Revision 1.80 2000/10/18 15:54:58 ht
1347: # make effort to check 'fixed' attribute values
1348: #
1.80 ht 1349: # Revision 1.79 2000/10/17 13:35:41 ht
1350: # put switch on warnings, default is don't
1351: #
1.79 ht 1352: # Revision 1.78 2000/10/17 12:45:15 ht
1353: # try to catch and log all crashes
1354: # replace stale reference to atribute.characters
1355: #
1.78 ht 1356: # Revision 1.77 2000/09/28 15:54:50 ht
1357: # schema error count includes all errors, not just those found at prep
1358: # time
1359: #
1.77 ht 1360: # Revision 1.76 2000/09/28 15:09:14 ht
1361: # try catching and returning any crashes
1362: #
1.76 ht 1363: # Revision 1.75 2000/09/28 08:41:57 ht
1364: # add usage message
1365: # add -o outfile cmd line arg
1366: #
1.75 ht 1367: # Revision 1.74 2000/09/27 13:48:47 richard
1368: # Use infoset-like names for slots (now provided in XML.py) to reduce
1369: # differences with infoset-based version.
1370: #
1.74 richard 1371: # Revision 1.73 2000/09/27 12:22:22 richard
1372: # correct element.name to element.local in an error message
1373: #
1.73 richard 1374: # Revision 1.72 2000/09/26 14:29:36 richard
1375: # Oops, didn't change AbInitio to XMLSchema.AbInitio when moving methods
1376: #
1.72 richard 1377: # Revision 1.71 2000/09/26 14:05:28 richard
1378: # Move checkString methods from XMLSchema.py, because they may need to look
1379: # at *instance* in-scope namespaces
1380: #
1.71 richard 1381: # Revision 1.70 2000/09/26 13:38:49 ht
1382: # protect against undefined list itemType/union memberType
1383: #
1.70 ht 1384: # Revision 1.69 2000/09/23 11:17:31 ht
1385: # merge in CR branch
1386: #
1.69 ht 1387:
1388: # Revision 1.68 2000/09/23 11:14:26 ht
1389: # towards merge in CR branch
1390: #
1.68 ht 1391: # Revision 1.66.2.3 2000/09/21 09:14:33 ht
1392: # property name change
1393: #
1394: # Revision 1.66.2.2 2000/09/11 12:23:27 ht
1395: # Move to branch: more debug in vv crash
1396: #
1397: # Revision 1.68 2000/09/03 15:57:23 ht
1398: # more debug in vv crash
1399:
1400: # Revision 1.67 2000/09/11 12:59:09 ht
1401: # allow stdin,
1402: # fix stupid bug missing third schema on command line
1403:
1404: # Revision 1.67 2000/08/31 11:48:41 ht
1405: # Direct support for validating lists and unions
1406:
1.67 ht 1407: # Revision 1.66 2000/08/22 13:11:30 ht
1408: # handle type w/o qname as document validation type
1409: # remove special treatment for AbInitio simple types on elements,
1410: # thereby fixing list validation bug
1.69 ht 1411:
1412: # Revision 1.66.2.3 2000/09/21 09:14:33 ht
1413: # property name change
1.67 ht 1414: #
1.69 ht 1415: # Revision 1.66.2.2 2000/09/11 12:23:27 ht
1416: # Move to branch: more debug in vv crash
1417: #
1418: # Revision 1.68 2000/09/03 15:57:23 ht
1419: # more debug in vv crash
1420: #
1421: # Revision 1.67 2000/08/31 11:48:41 ht
1422: # Direct support for validating lists and unions
1423: #
1424:
1.66 ht 1425: # Revision 1.66 2000/08/22 13:11:30 ht
1426: # handle type w/o qname as document validation type
1.65 ht 1427: # remove special treatment for AbInitio simple types on elements,
1.64 ht 1428: # thereby fixing list validation bug
1429: #
1430: # Revision 1.65 2000/07/12 09:31:58 ht
1.63 ht 1431: # try harder to always have a schema
1432: #
1433: # Revision 1.64 2000/07/10 14:39:02 ht
1434: # prepare for fileinfo to runit
1.62 ht 1435: #
1436: # Revision 1.63 2000/07/05 09:05:37 ht
1437: # change name to PyLTXML
1.61 ht 1438: #
1439: # Revision 1.62 2000/07/03 09:37:38 ht
1440: # bail out if textonly has elt daughter(s)
1.60 ht 1441: # add missing import
1442: #
1443: # Revision 1.61 2000/06/27 09:25:51 ht
1.59 ht 1444: # attempt to handle interaction between xsi:type and <any>
1445: #
1446: # Revision 1.60 2000/06/24 11:17:07 ht
1.58 ht 1447: # fix bug in unqualified xsi:type
1448: #
1449: # Revision 1.59 2000/06/22 10:31:33 ht
1450: # Bug in unique processing -- broke on missing field
1451: #
1452: # Revision 1.58 2000/06/20 08:07:42 ht
1453: # merge xmlout branches back in to main line
1454: #
1455:
1456: # Revision 1.57 2000/05/18 08:01:25 ht
1457: # fix bug in handling of xsi:type
1458: #
1459: # Revision 1.56 2000/05/14 12:19:34 ht
1460: # add context to checkSting calls
1461: #
1462: # Revision 1.55 2000/05/11 11:55:57 ht
1463: # just better handling of lax validation from other branch
1464: #
1465: # Revision 1.54.2.16 2000/06/15 16:03:20 ht
1466: # cover several missing definition cases
1467: #
1468: # Revision 1.54.2.15 2000/06/03 16:29:30 ht
1469: # oops, removing debugging comment
1470: #
1471: # Revision 1.54.2.14 2000/06/03 13:45:55 ht
1472: # catch arity bug in xsi:schemaLoc
1473: #
1474: # Revision 1.54.2.13 2000/05/30 09:35:43 ht
1475: # fix encoding bug when things break down altogether
1476: #
1477: # Revision 1.54.2.12 2000/05/29 08:46:53 ht
1478: # strong enforcement of nullable
1479: # add error codes to all errors
1480: # remove remaining __class__ tests
1481: # change error reporting wrt disallowed content
1482: #
1483: # Revision 1.54.2.11 2000/05/24 20:46:47 ht
1484: # make validateText a method, split across SimpleType and AbInitio
1485: #
1486: # Revision 1.54.2.10 2000/05/24 12:03:28 ht
1487: # modest effort to validate list types
1488: # fix bug in noNamespaceSchemaLocation handling at validation time
1489: #
1490: # Revision 1.54.2.9 2000/05/22 16:11:52 ht
1491: # use OpenStream, take more control of encoding
1492: #
1493: # Revision 1.54.2.8 2000/05/18 17:37:40 ht
1494: # parameterise stylesheet,
1495: # remove formatting from xsv:xsv attributes,
1496: # add namespace decl
1497: #
1498: # Revision 1.54.2.7 2000/05/18 07:59:48 ht
1499: # fix xsi:type validation bug
1500: #
1501: # Revision 1.54.2.6 2000/05/16 16:31:11 ht
1502: # fix bug handling un-typed element declarations == urType validation
1503: #
1504: # Revision 1.54.2.5 2000/05/14 12:29:59 ht
1505: # merge QName checking from main branch
1506: #
1507: # Revision 1.54.2.4 2000/05/12 15:15:01 ht
1508: # process keys even if type is simple,
1509: # add a few codes to get started
1510: #
1511: # Revision 1.54.2.3 2000/05/11 13:59:11 ht
1512: # convert verror/vwarn to produce elements
1513: # eliminate a few special error outputs in favour of special
1514: # sub-elements
1.57 ht 1515: #
1516: # Revision 1.54.2.2 2000/05/11 11:14:00 ht
1517: # more error protection
1.56 ht 1518: # handle lax recursively and at the start
1519: #
1520: # Revision 1.54.2.1 2000/05/10 11:36:47 ht
1.55 ht 1521: # begin converting to XML output
1522: #
1523: # Revision 1.56 2000/05/14 12:19:34 ht
1.54 ht 1524: # add context to checkSting calls
1525: #
1526: # Revision 1.55 2000/05/11 11:55:57 ht
1527: # just better handling of lax validation from other branch
1.53 ht 1528: #
1529: # Revision 1.54 2000/05/09 14:52:52 ht
1530: # Check for strings in a way that works with or without 16-bit support
1.52 richard 1531: #
1532: # Revision 1.53 2000/05/09 12:27:58 ht
1533: # replace our hack with python's url parsing stuff
1.51 ht 1534: # make f global for debugging
1535: #
1536: # Revision 1.52 2000/05/05 15:15:45 richard
1.50 richard 1537: # wrong (?) elt arg to verror in validateKeyRefs
1538: #
1539: # Revision 1.51 2000/05/04 07:56:35 ht
1.49 ht 1540: # Fix typo in opportunistic attribute validation
1541: #
1542: # Revision 1.50 2000/05/01 15:07:00 richard
1.48 richard 1543: # bug fix schema -> key.schema
1544: #
1545: # Revision 1.49 2000/05/01 10:05:43 ht
1546: # catch various missing file errors more gracefully
1.47 richard 1547: #
1548: # Revision 1.48 2000/04/28 15:40:01 richard
1549: # Implement xsi:null (still don't check nullable)
1.46 ht 1550: #
1551: # Revision 1.47 2000/04/28 15:11:23 richard
1552: # allow xsi: attributes on simple type
1553: # moved eltDecl code up validateElement ready for implementing xsi:null
1.45 ht 1554: #
1555: # Revision 1.46 2000/04/27 09:41:18 ht
1556: # remove raw types from error messages
1.44 ht 1557: #
1558: # Revision 1.45 2000/04/27 09:30:21 ht
1559: # check that inputs are actually schemas,
1560: # remove schema arg to doImport, checkInSchema
1561: #
1562: # Revision 1.44 2000/04/26 13:00:40 ht
1.43 ht 1563: # add copyright
1564: #
1565: # Revision 1.43 2000/04/24 20:46:40 ht
1.42 ht 1566: # cleanup residual bugs with massive rename,
1567: # rename Any to Wildcard,
1568: # replace AnyAttribute with Wildcard,
1569: # get validation of Wildcard working in both element and attribute contexts
1.41 ht 1570: #
1571: # Revision 1.42 2000/04/24 15:08:34 ht
1572: # minor glitches, tiny.xml works again
1.40 ht 1573: #
1574: # Revision 1.41 2000/04/24 15:00:09 ht
1575: # wholesale name changes -- init. caps for all classes,
1.39 ht 1576: # schema.py -> XMLSchema.py
1577: #
1578: # Revision 1.40 2000/04/24 11:09:17 ht
1.38 ht 1579: # make version string universally available
1580: #
1581: # Revision 1.39 2000/04/24 10:06:59 ht
1.37 ht 1582: # add version info to message
1583: #
1584: # Revision 1.38 2000/04/24 10:02:39 ht
1585: # change invocation message
1.36 ht 1586: #
1587: # Revision 1.37 2000/04/24 09:41:43 ht
1588: # clean up invocation some more, add k arg't to runit
1.35 ht 1589: #
1590: # Revision 1.36 2000/04/21 09:32:21 ht
1591: # another dose of resolveURL
1.34 ht 1592: # use tiny only if run from command line
1593: #
1594: # Revision 1.35 2000/04/20 22:12:43 ht
1.33 ht 1595: # use resolveURL on input, schemaLocs
1596: #
1597: # Revision 1.34 2000/04/20 15:45:08 ht
1598: # better handling of use of ns uri for loc
1599: #
1600: # Revision 1.33 2000/04/20 14:26:59 ht
1601: # merge in private and comp branches
1602: #
1603: # Revision 1.32.2.5 2000/04/20 14:25:54 ht
1604: # merge in comp branch
1605: #
1606: # Revision 1.32.2.4.2.9 2000/04/20 14:22:39 ht
1607: # manage document validation schema creation and search better
1608: #
1609: # Revision 1.32.2.4.2.8 2000/04/20 12:03:21 ht
1610: # Remove a few lingering effectiveTypes
1611: # Allow better for absent types etc.
1612: #
1613: # Revision 1.32.2.4.2.7 2000/04/14 21:18:27 ht
1614: # minor attr names/path changes to track schema
1615: #
1616: # Revision 1.32.2.4.2.6 2000/04/13 23:04:39 ht
1617: # allow for urType as simple type (?)
1618: # track Any->AnyWrap change
1619: #
1620: # Revision 1.32.2.4.2.5 2000/04/12 17:29:37 ht
1621: # begin work on model merger,
1622: #
1623: # Revision 1.32.2.4.2.4 2000/04/11 18:13:17 ht
1624: # interpolate attributeUse between complexType and attributeDeclaration,
1625: # parallel to particle
1626: #
1627: # Revision 1.32.2.4.2.3 2000/04/10 15:48:46 ht
1628: # put modest attribute validation in place
1629: #
1630: # Revision 1.32.2.4.2.2 2000/04/09 16:13:26 ht
1631: # working on complex type, attribute;
1632: # back out component.qname
1633: #
1634: # Revision 1.32.2.4.2.1 2000/04/05 12:12:36 ht
1635: # accommodate changes in schema.py
1636: #
1637: # Revision 1.32.2.4 2000/04/01 18:01:25 ht
1638: # various minor compatibility fixes
1639: #
1640: # Revision 1.32.2.3 2000/03/25 12:12:27 ht
1641: # restructure error handling/reporting;
1642: # allow for switching 208 on and off
1643: #
1644: # Revision 1.32.2.2 2000/03/21 15:57:23 ht
1645: # fix bug in skip,
1.32 ht 1646: # allow 208 override
1647: #
1648: # Revision 1.32.2.1 2000/03/20 17:22:52 ht
1649: # better coverage of <any>, including beginning of processcontents
1650: #
1651: # Revision 1.33 2000/03/20 17:20:53 ht
1652: # better coverage of <any>, including beginning of processcontents
1653: #
1654: # Revision 1.32 2000/03/08 15:28:46 ht
1655: # merge private branches back into public after 20000225 release
1656: #
1657: # Revision 1.31.2.3 2000/02/24 23:40:32 ht
1658: # fix any bug
1659: #
1660: # Revision 1.31.2.2 2000/02/21 09:18:13 ht
1661: # bug in <any> handling
1662: #
1.31 richard 1663: # Revision 1.31.2.1 2000/02/08 21:43:39 ht
1664: # fork private branch to track internal drafts
1665: # change calling sequence of checkinSchema
1.30 richard 1666: #
1667: # Revision 1.31.1.1 2000/02/08 13:54:25 ht
1668: # fork branch for non-public changes
1.29 ht 1669: # calling sequence to checkinSchema changed
1670: #
1671: # Revision 1.31 2000/01/13 16:55:42 richard
1672: # Finally do something with xsi:type
1.28 ht 1673: #
1674: # Revision 1.30 2000/01/10 17:36:34 richard
1675: # changes for xsi:schemaLocation
1.27 richard 1676: #
1677: # Revision 1.29 2000/01/08 23:33:50 ht
1678: # towards support for xsi:schemaLocation
1.26 ht 1679: #
1680: # Revision 1.28 2000/01/08 12:07:38 ht
1681: # Change command-line arg sequence in preparation for use of schemaLocation!!!!!
1.25 ht 1682: # Add debug printout for schemaLocation for now
1683: #
1684: # Revision 1.27 2000/01/07 17:08:26 richard
1685: # start on xsi:type
1686: #
1.24 ht 1687: # Revision 1.26 2000/01/06 14:59:38 ht
1.1 ht 1688: # fix command line bug, display args on entry
1689: #
1690: # Revision 1.25 2000/01/06 14:38:56 ht
1691: # detect cross-scope keyref and signal error
1692: #
1693: # Revision 1.24 2000/01/03 17:02:37 ht
1694: # Include result of sub-ordinate key checking in overall result
1695: # Accommodate new calling sequence for xpath.find
1696: # add Log and Id
1697: #
1698: #
Webmaster