1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Copyright 1999-2004 The Apache Software Foundation. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 package com.sun.org.apache.xerces.internal.impl.xs; 22 23 import java.util.Collections; 24 import java.util.Comparator; 25 import java.util.Vector; 26 27 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; 28 import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException; 29 import com.sun.org.apache.xerces.internal.impl.dv.ValidatedInfo; 30 import com.sun.org.apache.xerces.internal.impl.dv.ValidationContext; 31 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType; 32 import com.sun.org.apache.xerces.internal.impl.xs.models.CMBuilder; 33 import com.sun.org.apache.xerces.internal.impl.xs.models.XSCMValidator; 34 import com.sun.org.apache.xerces.internal.impl.xs.util.SimpleLocator; 35 import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl; 36 import com.sun.org.apache.xerces.internal.util.SymbolHash; 37 import com.sun.org.apache.xerces.internal.xs.XSConstants; 38 import com.sun.org.apache.xerces.internal.xs.XSObjectList; 39 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition; 40 41 /** 42 * Constaints shared by traversers and validator 43 * 44 * @xerces.internal 45 * 46 * @author Sandy Gao, IBM 47 * 48 */ 49 public class XSConstraints { 50 51 // IHR: Visited on 2006-11-17 52 // Added a boolean return value to particleValidRestriction (it was a void function) 53 // to help the checkRecurseLax to know when expansion has happened and no order is required 54 // (IHR@xbrl.org) (Ignacio@Hernandez-Ros.com) 55 56 static final int OCCURRENCE_UNKNOWN = SchemaSymbols.OCCURRENCE_UNBOUNDED-1; 57 static final XSSimpleType STRING_TYPE = (XSSimpleType)SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(SchemaSymbols.ATTVAL_STRING); 58 59 private static XSParticleDecl fEmptyParticle = null; 60 public static XSParticleDecl getEmptySequence() { 61 if (fEmptyParticle == null) { 62 XSModelGroupImpl group = new XSModelGroupImpl(); 63 group.fCompositor = XSModelGroupImpl.MODELGROUP_SEQUENCE; 64 group.fParticleCount = 0; 65 group.fParticles = null; 66 group.fAnnotations = XSObjectListImpl.EMPTY_LIST; 67 XSParticleDecl particle = new XSParticleDecl(); 68 particle.fType = XSParticleDecl.PARTICLE_MODELGROUP; 69 particle.fValue = group; 70 particle.fAnnotations = XSObjectListImpl.EMPTY_LIST; 71 fEmptyParticle = particle; 72 } 73 return fEmptyParticle; 74 } 75 76 private static final Comparator ELEMENT_PARTICLE_COMPARATOR = new Comparator() { 77 78 public int compare(Object o1, Object o2) { 79 XSParticleDecl pDecl1 = (XSParticleDecl) o1; 80 XSParticleDecl pDecl2 = (XSParticleDecl) o2; 81 XSElementDecl decl1 = (XSElementDecl) pDecl1.fValue; 82 XSElementDecl decl2 = (XSElementDecl) pDecl2.fValue; 83 84 String namespace1 = decl1.getNamespace(); 85 String namespace2 = decl2.getNamespace(); 86 String name1 = decl1.getName(); 87 String name2 = decl2.getName(); 88 89 boolean sameNamespace = (namespace1 == namespace2); 90 int namespaceComparison = 0; 91 92 if (!sameNamespace) { 93 if (namespace1 != null) { 94 if (namespace2 != null){ 95 namespaceComparison = namespace1.compareTo(namespace2); 96 } 97 else { 98 namespaceComparison = 1; 99 } 100 } 101 else { 102 namespaceComparison = -1; 103 } 104 } 105 //This assumes that the names are never null. 106 return namespaceComparison != 0 ? namespaceComparison : name1.compareTo(name2); 107 } 108 }; 109 110 /** 111 * check whether derived is valid derived from base, given a subset 112 * of {restriction, extension}.B 113 */ 114 public static boolean checkTypeDerivationOk(XSTypeDefinition derived, XSTypeDefinition base, short block) { 115 // if derived is anyType, then it's valid only if base is anyType too 116 if (derived == SchemaGrammar.fAnyType) 117 return derived == base; 118 // if derived is anySimpleType, then it's valid only if the base 119 // is ur-type 120 if (derived == SchemaGrammar.fAnySimpleType) { 121 return (base == SchemaGrammar.fAnyType || 122 base == SchemaGrammar.fAnySimpleType); 123 } 124 125 // if derived is simple type 126 if (derived.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { 127 // if base is complex type 128 if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { 129 // if base is anyType, change base to anySimpleType, 130 // otherwise, not valid 131 if (base == SchemaGrammar.fAnyType) 132 base = SchemaGrammar.fAnySimpleType; 133 else 134 return false; 135 } 136 return checkSimpleDerivation((XSSimpleType)derived, 137 (XSSimpleType)base, block); 138 } 139 else { 140 return checkComplexDerivation((XSComplexTypeDecl)derived, base, block); 141 } 142 } 143 144 /** 145 * check whether simple type derived is valid derived from base, 146 * given a subset of {restriction, extension}. 147 */ 148 public static boolean checkSimpleDerivationOk(XSSimpleType derived, XSTypeDefinition base, short block) { 149 // if derived is anySimpleType, then it's valid only if the base 150 // is ur-type 151 if (derived == SchemaGrammar.fAnySimpleType) { 152 return (base == SchemaGrammar.fAnyType || 153 base == SchemaGrammar.fAnySimpleType); 154 } 155 156 // if base is complex type 157 if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { 158 // if base is anyType, change base to anySimpleType, 159 // otherwise, not valid 160 if (base == SchemaGrammar.fAnyType) 161 base = SchemaGrammar.fAnySimpleType; 162 else 163 return false; 164 } 165 return checkSimpleDerivation((XSSimpleType)derived, 166 (XSSimpleType)base, block); 167 } 168 169 /** 170 * check whether complex type derived is valid derived from base, 171 * given a subset of {restriction, extension}. 172 */ 173 public static boolean checkComplexDerivationOk(XSComplexTypeDecl derived, XSTypeDefinition base, short block) { 174 // if derived is anyType, then it's valid only if base is anyType too 175 if (derived == SchemaGrammar.fAnyType) 176 return derived == base; 177 return checkComplexDerivation((XSComplexTypeDecl)derived, base, block); 178 } 179 180 /** 181 * Note: this will be a private method, and it assumes that derived is not 182 * anySimpleType, and base is not anyType. Another method will be 183 * introduced for public use, which will call this method. 184 */ 185 private static boolean checkSimpleDerivation(XSSimpleType derived, XSSimpleType base, short block) { 186 // 1 They are the same type definition. 187 if (derived == base) 188 return true; 189 190 // 2 All of the following must be true: 191 // 2.1 restriction is not in the subset, or in the {final} of its own {base type definition}; 192 if ((block & XSConstants.DERIVATION_RESTRICTION) != 0 || 193 (derived.getBaseType().getFinal() & XSConstants.DERIVATION_RESTRICTION) != 0) { 194 return false; 195 } 196 197 // 2.2 One of the following must be true: 198 // 2.2.1 D's base type definition is B. 199 XSSimpleType directBase = (XSSimpleType)derived.getBaseType(); 200 if (directBase == base) 201 return true; 202 203 // 2.2.2 D's base type definition is not the simple ur-type definition and is validly derived from B given the subset, as defined by this constraint. 204 if (directBase != SchemaGrammar.fAnySimpleType && 205 checkSimpleDerivation(directBase, base, block)) { 206 return true; 207 } 208 209 // 2.2.3 D's {variety} is list or union and B is the simple ur-type definition. 210 if ((derived.getVariety() == XSSimpleType.VARIETY_LIST || 211 derived.getVariety() == XSSimpleType.VARIETY_UNION) && 212 base == SchemaGrammar.fAnySimpleType) { 213 return true; 214 } 215 216 // 2.2.4 B's {variety} is union and D is validly derived from a type definition in B's {member type definitions} given the subset, as defined by this constraint. 217 if (base.getVariety() == XSSimpleType.VARIETY_UNION) { 218 XSObjectList subUnionMemberDV = base.getMemberTypes(); 219 int subUnionSize = subUnionMemberDV.getLength(); 220 for (int i=0; i<subUnionSize; i++) { 221 base = (XSSimpleType)subUnionMemberDV.item(i); 222 if (checkSimpleDerivation(derived, base, block)) 223 return true; 224 } 225 } 226 227 return false; 228 } 229 230 /** 231 * Note: this will be a private method, and it assumes that derived is not 232 * anyType. Another method will be introduced for public use, 233 * which will call this method. 234 */ 235 private static boolean checkComplexDerivation(XSComplexTypeDecl derived, XSTypeDefinition base, short block) { 236 // 2.1 B and D must be the same type definition. 237 if (derived == base) 238 return true; 239 240 // 1 If B and D are not the same type definition, then the {derivation method} of D must not be in the subset. 241 if ((derived.fDerivedBy & block) != 0) 242 return false; 243 244 // 2 One of the following must be true: 245 XSTypeDefinition directBase = derived.fBaseType; 246 // 2.2 B must be D's {base type definition}. 247 if (directBase == base) 248 return true; 249 250 // 2.3 All of the following must be true: 251 // 2.3.1 D's {base type definition} must not be the ur-type definition. 252 if (directBase == SchemaGrammar.fAnyType || 253 directBase == SchemaGrammar.fAnySimpleType) { 254 return false; 255 } 256 257 // 2.3.2 The appropriate case among the following must be true: 258 // 2.3.2.1 If D's {base type definition} is complex, then it must be validly derived from B given the subset as defined by this constraint. 259 if (directBase.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) 260 return checkComplexDerivation((XSComplexTypeDecl)directBase, base, block); 261 262 // 2.3.2.2 If D's {base type definition} is simple, then it must be validly derived from B given the subset as defined in Type Derivation OK (Simple) (3.14.6). 263 if (directBase.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { 264 // if base is complex type 265 if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) { 266 // if base is anyType, change base to anySimpleType, 267 // otherwise, not valid 268 if (base == SchemaGrammar.fAnyType) 269 base = SchemaGrammar.fAnySimpleType; 270 else 271 return false; 272 } 273 return checkSimpleDerivation((XSSimpleType)directBase, 274 (XSSimpleType)base, block); 275 } 276 277 return false; 278 } 279 280 /** 281 * check whether a value is a valid default for some type 282 * returns the compiled form of the value 283 * The parameter value could be either a String or a ValidatedInfo object 284 */ 285 public static Object ElementDefaultValidImmediate(XSTypeDefinition type, String value, ValidationContext context, ValidatedInfo vinfo) { 286 287 XSSimpleType dv = null; 288 289 // e-props-correct 290 // For a string to be a valid default with respect to a type definition the appropriate case among the following must be true: 291 // 1 If the type definition is a simple type definition, then the string must be valid with respect to that definition as defined by String Valid (3.14.4). 292 if (type.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { 293 dv = (XSSimpleType)type; 294 } 295 296 // 2 If the type definition is a complex type definition, then all of the following must be true: 297 else { 298 // 2.1 its {content type} must be a simple type definition or mixed. 299 XSComplexTypeDecl ctype = (XSComplexTypeDecl)type; 300 // 2.2 The appropriate case among the following must be true: 301 // 2.2.1 If the {content type} is a simple type definition, then the string must be valid with respect to that simple type definition as defined by String Valid (3.14.4). 302 if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) { 303 dv = ctype.fXSSimpleType; 304 } 305 // 2.2.2 If the {content type} is mixed, then the {content type}'s particle must be emptiable as defined by Particle Emptiable (3.9.6). 306 else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED) { 307 if (!((XSParticleDecl)ctype.getParticle()).emptiable()) 308 return null; 309 } 310 else { 311 return null; 312 } 313 } 314 315 // get the simple type declaration, and validate 316 Object actualValue = null; 317 if (dv == null) { 318 // complex type with mixed. to make sure that we store correct 319 // information in vinfo and return the correct value, we use 320 // "string" type for validation 321 dv = STRING_TYPE; 322 } 323 try { 324 // validate the original lexical rep, and set the actual value 325 actualValue = dv.validate(value, context, vinfo); 326 // validate the canonical lexical rep 327 if (vinfo != null) 328 actualValue = dv.validate(vinfo.stringValue(), context, vinfo); 329 } catch (InvalidDatatypeValueException ide) { 330 return null; 331 } 332 333 return actualValue; 334 } 335 336 static void reportSchemaError(XMLErrorReporter errorReporter, 337 SimpleLocator loc, 338 String key, Object[] args) { 339 if (loc != null) { 340 errorReporter.reportError(loc, XSMessageFormatter.SCHEMA_DOMAIN, 341 key, args, XMLErrorReporter.SEVERITY_ERROR); 342 } 343 else { 344 errorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN, 345 key, args, XMLErrorReporter.SEVERITY_ERROR); 346 } 347 } 348 349 /** 350 * used to check the 3 constraints against each complex type 351 * (should be each model group): 352 * Unique Particle Attribution, Particle Derivation (Restriction), 353 * Element Declrations Consistent. 354 */ 355 public static void fullSchemaChecking(XSGrammarBucket grammarBucket, 356 SubstitutionGroupHandler SGHandler, 357 CMBuilder cmBuilder, 358 XMLErrorReporter errorReporter) { 359 // get all grammars, and put all substitution group information 360 // in the substitution group handler 361 SchemaGrammar[] grammars = grammarBucket.getGrammars(); 362 for (int i = grammars.length-1; i >= 0; i--) { 363 SGHandler.addSubstitutionGroup(grammars[i].getSubstitutionGroups()); 364 } 365 366 XSParticleDecl fakeDerived = new XSParticleDecl(); 367 XSParticleDecl fakeBase = new XSParticleDecl(); 368 fakeDerived.fType = XSParticleDecl.PARTICLE_MODELGROUP; 369 fakeBase.fType = XSParticleDecl.PARTICLE_MODELGROUP; 370 // before worrying about complexTypes, let's get 371 // groups redefined by restriction out of the way. 372 for (int g = grammars.length-1; g >= 0; g--) { 373 XSGroupDecl [] redefinedGroups = grammars[g].getRedefinedGroupDecls(); 374 SimpleLocator [] rgLocators = grammars[g].getRGLocators(); 375 for(int i=0; i<redefinedGroups.length; ) { 376 XSGroupDecl derivedGrp = redefinedGroups[i++]; 377 XSModelGroupImpl derivedMG = derivedGrp.fModelGroup; 378 XSGroupDecl baseGrp = redefinedGroups[i++]; 379 XSModelGroupImpl baseMG = baseGrp.fModelGroup; 380 fakeDerived.fValue = derivedMG; 381 fakeBase.fValue = baseMG; 382 if(baseMG == null) { 383 if(derivedMG != null) { // can't be a restriction! 384 reportSchemaError(errorReporter, rgLocators[i/2-1], 385 "src-redefine.6.2.2", 386 new Object[]{derivedGrp.fName, "rcase-Recurse.2"}); 387 } 388 } else if (derivedMG == null) { 389 if (!fakeBase.emptiable()) { 390 reportSchemaError(errorReporter, rgLocators[i/2-1], 391 "src-redefine.6.2.2", 392 new Object[]{derivedGrp.fName, "rcase-Recurse.2"}); 393 } 394 } else { 395 try { 396 particleValidRestriction(fakeDerived, SGHandler, fakeBase, SGHandler); 397 } catch (XMLSchemaException e) { 398 String key = e.getKey(); 399 reportSchemaError(errorReporter, rgLocators[i/2-1], 400 key, 401 e.getArgs()); 402 reportSchemaError(errorReporter, rgLocators[i/2-1], 403 "src-redefine.6.2.2", 404 new Object[]{derivedGrp.fName, key}); 405 } 406 } 407 } 408 } 409 410 // for each complex type, check the 3 constraints. 411 // types need to be checked 412 XSComplexTypeDecl[] types; 413 SimpleLocator [] ctLocators; 414 // to hold the errors 415 // REVISIT: do we want to report all errors? or just one? 416 //XMLSchemaError1D errors = new XMLSchemaError1D(); 417 // whether need to check this type again; 418 // whether only do UPA checking 419 boolean further, fullChecked; 420 // if do all checkings, how many need to be checked again. 421 int keepType; 422 // i: grammar; j: type; k: error 423 // for all grammars 424 SymbolHash elemTable = new SymbolHash(); 425 for (int i = grammars.length-1, j; i >= 0; i--) { 426 // get whether to skip EDC, and types need to be checked 427 keepType = 0; 428 fullChecked = grammars[i].fFullChecked; 429 types = grammars[i].getUncheckedComplexTypeDecls(); 430 ctLocators = grammars[i].getUncheckedCTLocators(); 431 // for each type 432 for (j = 0; j < types.length; j++) { 433 // if we've already full-checked this grammar, then 434 // skip the EDC constraint 435 if (!fullChecked) { 436 // 1. Element Decl Consistent 437 if (types[j].fParticle!=null) { 438 elemTable.clear(); 439 try { 440 checkElementDeclsConsistent(types[j], types[j].fParticle, 441 elemTable, SGHandler); 442 } 443 catch (XMLSchemaException e) { 444 reportSchemaError(errorReporter, ctLocators[j], 445 e.getKey(), 446 e.getArgs()); 447 } 448 } 449 } 450 451 // 2. Particle Derivation 452 453 if (types[j].fBaseType != null && 454 types[j].fBaseType != SchemaGrammar.fAnyType && 455 types[j].fDerivedBy == XSConstants.DERIVATION_RESTRICTION && 456 (types[j].fBaseType instanceof XSComplexTypeDecl)) { 457 458 XSParticleDecl derivedParticle=types[j].fParticle; 459 XSParticleDecl baseParticle= 460 ((XSComplexTypeDecl)(types[j].fBaseType)).fParticle; 461 if (derivedParticle==null) { 462 if (baseParticle!=null && !baseParticle.emptiable()) { 463 reportSchemaError(errorReporter,ctLocators[j], 464 "derivation-ok-restriction.5.3.2", 465 new Object[]{types[j].fName, types[j].fBaseType.getName()}); 466 } 467 } 468 else if (baseParticle!=null) { 469 try { 470 particleValidRestriction(types[j].fParticle, 471 SGHandler, 472 ((XSComplexTypeDecl)(types[j].fBaseType)).fParticle, 473 SGHandler); 474 } catch (XMLSchemaException e) { 475 reportSchemaError(errorReporter, ctLocators[j], 476 e.getKey(), 477 e.getArgs()); 478 reportSchemaError(errorReporter, ctLocators[j], 479 "derivation-ok-restriction.5.4.2", 480 new Object[]{types[j].fName}); 481 } 482 } 483 else { 484 reportSchemaError(errorReporter, ctLocators[j], 485 "derivation-ok-restriction.5.4.2", 486 new Object[]{types[j].fName}); 487 } 488 } 489 // 3. UPA 490 // get the content model and check UPA 491 XSCMValidator cm = types[j].getContentModel(cmBuilder); 492 further = false; 493 if (cm != null) { 494 try { 495 further = cm.checkUniqueParticleAttribution(SGHandler); 496 } catch (XMLSchemaException e) { 497 reportSchemaError(errorReporter, ctLocators[j], 498 e.getKey(), 499 e.getArgs()); 500 } 501 } 502 // now report all errors 503 // REVISIT: do we want to report all errors? or just one? 504 /*for (k = errors.getErrorCodeNum()-1; k >= 0; k--) { 505 reportSchemaError(errorReporter, ctLocators[j], 506 errors.getErrorCode(k), 507 errors.getArgs(k)); 508 }*/ 509 510 // if we are doing all checkings, and this one needs further 511 // checking, store it in the type array. 512 if (!fullChecked && further) 513 types[keepType++] = types[j]; 514 515 // clear errors for the next type. 516 // REVISIT: do we want to report all errors? or just one? 517 //errors.clear(); 518 } 519 // we've done with the types in this grammar. if we are checking 520 // all constraints, need to trim type array to a proper size: 521 // only contain those need further checking. 522 // and mark this grammar that it only needs UPA checking. 523 if (!fullChecked) { 524 grammars[i].setUncheckedTypeNum(keepType); 525 grammars[i].fFullChecked = true; 526 } 527 } 528 } 529 530 /* 531 Check that a given particle is a valid restriction of a base particle. 532 */ 533 534 public static void checkElementDeclsConsistent(XSComplexTypeDecl type, 535 XSParticleDecl particle, 536 SymbolHash elemDeclHash, 537 SubstitutionGroupHandler sgHandler) 538 throws XMLSchemaException { 539 540 // check for elements in the tree with the same name and namespace 541 542 int pType = particle.fType; 543 544 if (pType == XSParticleDecl.PARTICLE_WILDCARD) 545 return; 546 547 if (pType == XSParticleDecl.PARTICLE_ELEMENT) { 548 XSElementDecl elem = (XSElementDecl)(particle.fValue); 549 findElemInTable(type, elem, elemDeclHash); 550 551 if (elem.fScope == XSConstants.SCOPE_GLOBAL) { 552 // Check for subsitution groups. 553 XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(elem); 554 for (int i = 0; i < subGroup.length; i++) { 555 findElemInTable(type, subGroup[i], elemDeclHash); 556 } 557 } 558 return; 559 } 560 561 XSModelGroupImpl group = (XSModelGroupImpl)particle.fValue; 562 for (int i = 0; i < group.fParticleCount; i++) 563 checkElementDeclsConsistent(type, group.fParticles[i], elemDeclHash, sgHandler); 564 } 565 566 public static void findElemInTable(XSComplexTypeDecl type, XSElementDecl elem, 567 SymbolHash elemDeclHash) 568 throws XMLSchemaException { 569 570 // How can we avoid this concat? LM. 571 String name = elem.fName + "," + elem.fTargetNamespace; 572 573 XSElementDecl existingElem = null; 574 if ((existingElem = (XSElementDecl)(elemDeclHash.get(name))) == null) { 575 // just add it in 576 elemDeclHash.put(name, elem); 577 } 578 else { 579 // If this is the same check element, we're O.K. 580 if (elem == existingElem) 581 return; 582 583 if (elem.fType != existingElem.fType) { 584 // Types are not the same 585 throw new XMLSchemaException("cos-element-consistent", 586 new Object[] {type.fName, elem.fName}); 587 588 } 589 } 590 } 591 592 // Check that a given particle is a valid restriction of a base particle. 593 // 594 // IHR: 2006/11/17 595 // Returns a boolean indicating if there has been expansion of substitution group 596 // in the bParticle. 597 // With this information the checkRecurseLax function knows when is 598 // to keep the order and when to ignore it. 599 private static boolean particleValidRestriction(XSParticleDecl dParticle, 600 SubstitutionGroupHandler dSGHandler, 601 XSParticleDecl bParticle, 602 SubstitutionGroupHandler bSGHandler) 603 throws XMLSchemaException { 604 return particleValidRestriction(dParticle, dSGHandler, bParticle, bSGHandler, true); 605 } 606 607 private static boolean particleValidRestriction(XSParticleDecl dParticle, 608 SubstitutionGroupHandler dSGHandler, 609 XSParticleDecl bParticle, 610 SubstitutionGroupHandler bSGHandler, 611 boolean checkWCOccurrence) 612 throws XMLSchemaException { 613 614 Vector dChildren = null; 615 Vector bChildren = null; 616 int dMinEffectiveTotalRange=OCCURRENCE_UNKNOWN; 617 int dMaxEffectiveTotalRange=OCCURRENCE_UNKNOWN; 618 619 // By default there has been no expansion 620 boolean bExpansionHappened = false; 621 622 // Check for empty particles. If either base or derived particle is empty, 623 // (and the other isn't) it's an error. 624 if (dParticle.isEmpty() && !bParticle.emptiable()) { 625 throw new XMLSchemaException("cos-particle-restrict.a", null); 626 } 627 else if (!dParticle.isEmpty() && bParticle.isEmpty()) { 628 throw new XMLSchemaException("cos-particle-restrict.b", null); 629 } 630 631 // 632 // Do setup prior to invoking the Particle (Restriction) cases. 633 // This involves: 634 // - removing pointless occurrences for groups, and retrieving a vector of 635 // non-pointless children 636 // - turning top-level elements with substitution groups into CHOICE groups. 637 // 638 639 short dType = dParticle.fType; 640 // 641 // Handle pointless groups for the derived particle 642 // 643 if (dType == XSParticleDecl.PARTICLE_MODELGROUP) { 644 dType = ((XSModelGroupImpl)dParticle.fValue).fCompositor; 645 646 // Find a group, starting with this particle, with more than 1 child. There 647 // may be none, and the particle of interest trivially becomes an element or 648 // wildcard. 649 XSParticleDecl dtmp = getNonUnaryGroup(dParticle); 650 if (dtmp != dParticle) { 651 // Particle has been replaced. Retrieve new type info. 652 dParticle = dtmp; 653 dType = dParticle.fType; 654 if (dType == XSParticleDecl.PARTICLE_MODELGROUP) 655 dType = ((XSModelGroupImpl)dParticle.fValue).fCompositor; 656 } 657 658 // Fill in a vector with the children of the particle, removing any 659 // pointless model groups in the process. 660 dChildren = removePointlessChildren(dParticle); 661 } 662 663 int dMinOccurs = dParticle.fMinOccurs; 664 int dMaxOccurs = dParticle.fMaxOccurs; 665 666 // 667 // For elements which are the heads of substitution groups, treat as CHOICE 668 // 669 if (dSGHandler != null && dType == XSParticleDecl.PARTICLE_ELEMENT) { 670 XSElementDecl dElement = (XSElementDecl)dParticle.fValue; 671 672 if (dElement.fScope == XSConstants.SCOPE_GLOBAL) { 673 // Check for subsitution groups. Treat any element that has a 674 // subsitution group as a choice. Fill in the children vector with the 675 // members of the substitution group 676 XSElementDecl[] subGroup = dSGHandler.getSubstitutionGroup(dElement); 677 if (subGroup.length >0 ) { 678 // Now, set the type to be CHOICE. The "group" will have the same 679 // occurrence information as the original particle. 680 dType = XSModelGroupImpl.MODELGROUP_CHOICE; 681 dMinEffectiveTotalRange = dMinOccurs; 682 dMaxEffectiveTotalRange = dMaxOccurs; 683 684 // Fill in the vector of children 685 dChildren = new Vector(subGroup.length+1); 686 for (int i = 0; i < subGroup.length; i++) { 687 addElementToParticleVector(dChildren, subGroup[i]); 688 } 689 addElementToParticleVector(dChildren, dElement); 690 Collections.sort(dChildren, ELEMENT_PARTICLE_COMPARATOR); 691 692 // Set the handler to null, to indicate that we've finished handling 693 // substitution groups for this particle. 694 dSGHandler = null; 695 } 696 } 697 } 698 699 short bType = bParticle.fType; 700 // 701 // Handle pointless groups for the base particle 702 // 703 if (bType == XSParticleDecl.PARTICLE_MODELGROUP) { 704 bType = ((XSModelGroupImpl)bParticle.fValue).fCompositor; 705 706 // Find a group, starting with this particle, with more than 1 child. There 707 // may be none, and the particle of interest trivially becomes an element or 708 // wildcard. 709 XSParticleDecl btmp = getNonUnaryGroup(bParticle); 710 if (btmp != bParticle) { 711 // Particle has been replaced. Retrieve new type info. 712 bParticle = btmp; 713 bType = bParticle.fType; 714 if (bType == XSParticleDecl.PARTICLE_MODELGROUP) 715 bType = ((XSModelGroupImpl)bParticle.fValue).fCompositor; 716 } 717 718 // Fill in a vector with the children of the particle, removing any 719 // pointless model groups in the process. 720 bChildren = removePointlessChildren(bParticle); 721 } 722 723 int bMinOccurs = bParticle.fMinOccurs; 724 int bMaxOccurs = bParticle.fMaxOccurs; 725 726 if (bSGHandler != null && bType == XSParticleDecl.PARTICLE_ELEMENT) { 727 XSElementDecl bElement = (XSElementDecl)bParticle.fValue; 728 729 if (bElement.fScope == XSConstants.SCOPE_GLOBAL) { 730 // Check for subsitution groups. Treat any element that has a 731 // subsitution group as a choice. Fill in the children vector with the 732 // members of the substitution group 733 XSElementDecl[] bsubGroup = bSGHandler.getSubstitutionGroup(bElement); 734 if (bsubGroup.length >0 ) { 735 // Now, set the type to be CHOICE 736 bType = XSModelGroupImpl.MODELGROUP_CHOICE; 737 738 bChildren = new Vector(bsubGroup.length+1); 739 for (int i = 0; i < bsubGroup.length; i++) { 740 addElementToParticleVector(bChildren, bsubGroup[i]); 741 } 742 addElementToParticleVector(bChildren, bElement); 743 Collections.sort(bChildren, ELEMENT_PARTICLE_COMPARATOR); 744 // Set the handler to null, to indicate that we've finished handling 745 // substitution groups for this particle. 746 bSGHandler = null; 747 748 // if we are here expansion of bParticle happened 749 bExpansionHappened = true; 750 } 751 } 752 } 753 754 // 755 // O.K. - Figure out which particle derivation rule applies and call it 756 // 757 switch (dType) { 758 case XSParticleDecl.PARTICLE_ELEMENT: 759 { 760 switch (bType) { 761 762 // Elt:Elt NameAndTypeOK 763 case XSParticleDecl.PARTICLE_ELEMENT: 764 { 765 checkNameAndTypeOK((XSElementDecl)dParticle.fValue,dMinOccurs,dMaxOccurs, 766 (XSElementDecl)bParticle.fValue,bMinOccurs,bMaxOccurs); 767 return bExpansionHappened; 768 } 769 770 // Elt:Any NSCompat 771 case XSParticleDecl.PARTICLE_WILDCARD: 772 { 773 checkNSCompat((XSElementDecl)dParticle.fValue,dMinOccurs,dMaxOccurs, 774 (XSWildcardDecl)bParticle.fValue,bMinOccurs,bMaxOccurs, 775 checkWCOccurrence); 776 return bExpansionHappened; 777 } 778 779 // Elt:All RecurseAsIfGroup 780 case XSModelGroupImpl.MODELGROUP_CHOICE: 781 { 782 // Treat the element as if it were in a group of the same type 783 // as the base Particle 784 dChildren = new Vector(); 785 dChildren.addElement(dParticle); 786 787 checkRecurseLax(dChildren, 1, 1, dSGHandler, 788 bChildren, bMinOccurs, bMaxOccurs, bSGHandler); 789 return bExpansionHappened; 790 } 791 case XSModelGroupImpl.MODELGROUP_SEQUENCE: 792 case XSModelGroupImpl.MODELGROUP_ALL: 793 { 794 // Treat the element as if it were in a group of the same type 795 // as the base Particle 796 dChildren = new Vector(); 797 dChildren.addElement(dParticle); 798 799 checkRecurse(dChildren, 1, 1, dSGHandler, 800 bChildren, bMinOccurs, bMaxOccurs, bSGHandler); 801 return bExpansionHappened; 802 } 803 804 default: 805 { 806 throw new XMLSchemaException("Internal-Error", 807 new Object[]{"in particleValidRestriction"}); 808 } 809 } 810 } 811 812 case XSParticleDecl.PARTICLE_WILDCARD: 813 { 814 switch (bType) { 815 816 // Any:Any NSSubset 817 case XSParticleDecl.PARTICLE_WILDCARD: 818 { 819 checkNSSubset((XSWildcardDecl)dParticle.fValue, dMinOccurs, dMaxOccurs, 820 (XSWildcardDecl)bParticle.fValue, bMinOccurs, bMaxOccurs); 821 return bExpansionHappened; 822 } 823 824 case XSModelGroupImpl.MODELGROUP_CHOICE: 825 case XSModelGroupImpl.MODELGROUP_SEQUENCE: 826 case XSModelGroupImpl.MODELGROUP_ALL: 827 case XSParticleDecl.PARTICLE_ELEMENT: 828 { 829 throw new XMLSchemaException("cos-particle-restrict.2", 830 new Object[]{"any:choice,sequence,all,elt"}); 831 } 832 833 default: 834 { 835 throw new XMLSchemaException("Internal-Error", 836 new Object[]{"in particleValidRestriction"}); 837 } 838 } 839 } 840 841 case XSModelGroupImpl.MODELGROUP_ALL: 842 { 843 switch (bType) { 844 845 // All:Any NSRecurseCheckCardinality 846 case XSParticleDecl.PARTICLE_WILDCARD: 847 { 848 if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN) 849 dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange(); 850 if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN) 851 dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange(); 852 853 checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange, 854 dMaxEffectiveTotalRange, 855 dSGHandler, 856 bParticle,bMinOccurs,bMaxOccurs, 857 checkWCOccurrence); 858 859 return bExpansionHappened; 860 } 861 862 case XSModelGroupImpl.MODELGROUP_ALL: 863 { 864 checkRecurse(dChildren, dMinOccurs, dMaxOccurs, dSGHandler, 865 bChildren, bMinOccurs, bMaxOccurs, bSGHandler); 866 return bExpansionHappened; 867 } 868 869 case XSModelGroupImpl.MODELGROUP_CHOICE: 870 case XSModelGroupImpl.MODELGROUP_SEQUENCE: 871 case XSParticleDecl.PARTICLE_ELEMENT: 872 { 873 throw new XMLSchemaException("cos-particle-restrict.2", 874 new Object[]{"all:choice,sequence,elt"}); 875 } 876 877 default: 878 { 879 throw new XMLSchemaException("Internal-Error", 880 new Object[]{"in particleValidRestriction"}); 881 } 882 } 883 } 884 885 case XSModelGroupImpl.MODELGROUP_CHOICE: 886 { 887 switch (bType) { 888 889 // Choice:Any NSRecurseCheckCardinality 890 case XSParticleDecl.PARTICLE_WILDCARD: 891 { 892 if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN) 893 dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange(); 894 if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN) 895 dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange(); 896 897 checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange, 898 dMaxEffectiveTotalRange, 899 dSGHandler, 900 bParticle,bMinOccurs,bMaxOccurs, 901 checkWCOccurrence); 902 return bExpansionHappened; 903 } 904 905 case XSModelGroupImpl.MODELGROUP_CHOICE: 906 { 907 checkRecurseLax(dChildren, dMinOccurs, dMaxOccurs, dSGHandler, 908 bChildren, bMinOccurs, bMaxOccurs, bSGHandler); 909 return bExpansionHappened; 910 } 911 912 case XSModelGroupImpl.MODELGROUP_ALL: 913 case XSModelGroupImpl.MODELGROUP_SEQUENCE: 914 case XSParticleDecl.PARTICLE_ELEMENT: 915 { 916 throw new XMLSchemaException("cos-particle-restrict.2", 917 new Object[]{"choice:all,sequence,elt"}); 918 } 919 920 default: 921 { 922 throw new XMLSchemaException("Internal-Error", 923 new Object[]{"in particleValidRestriction"}); 924 } 925 } 926 } 927 928 929 case XSModelGroupImpl.MODELGROUP_SEQUENCE: 930 { 931 switch (bType) { 932 933 // Choice:Any NSRecurseCheckCardinality 934 case XSParticleDecl.PARTICLE_WILDCARD: 935 { 936 if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN) 937 dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange(); 938 if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN) 939 dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange(); 940 941 checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange, 942 dMaxEffectiveTotalRange, 943 dSGHandler, 944 bParticle,bMinOccurs,bMaxOccurs, 945 checkWCOccurrence); 946 return bExpansionHappened; 947 } 948 949 case XSModelGroupImpl.MODELGROUP_ALL: 950 { 951 checkRecurseUnordered(dChildren, dMinOccurs, dMaxOccurs, dSGHandler, 952 bChildren, bMinOccurs, bMaxOccurs, bSGHandler); 953 return bExpansionHappened; 954 } 955 956 case XSModelGroupImpl.MODELGROUP_SEQUENCE: 957 { 958 checkRecurse(dChildren, dMinOccurs, dMaxOccurs, dSGHandler, 959 bChildren, bMinOccurs, bMaxOccurs, bSGHandler); 960 return bExpansionHappened; 961 } 962 963 case XSModelGroupImpl.MODELGROUP_CHOICE: 964 { 965 int min1 = dMinOccurs * dChildren.size(); 966 int max1 = (dMaxOccurs == SchemaSymbols.OCCURRENCE_UNBOUNDED)? 967 dMaxOccurs : dMaxOccurs * dChildren.size(); 968 checkMapAndSum(dChildren, min1, max1, dSGHandler, 969 bChildren, bMinOccurs, bMaxOccurs, bSGHandler); 970 return bExpansionHappened; 971 } 972 973 case XSParticleDecl.PARTICLE_ELEMENT: 974 { 975 throw new XMLSchemaException("cos-particle-restrict.2", 976 new Object[]{"seq:elt"}); 977 } 978 979 default: 980 { 981 throw new XMLSchemaException("Internal-Error", 982 new Object[]{"in particleValidRestriction"}); 983 } 984 } 985 } 986 987 } 988 989 return bExpansionHappened; 990 } 991 992 private static void addElementToParticleVector (Vector v, XSElementDecl d) { 993 994 XSParticleDecl p = new XSParticleDecl(); 995 p.fValue = d; 996 p.fType = XSParticleDecl.PARTICLE_ELEMENT; 997 v.addElement(p); 998 999 } 1000 1001 private static XSParticleDecl getNonUnaryGroup(XSParticleDecl p) { 1002 1003 if (p.fType == XSParticleDecl.PARTICLE_ELEMENT || 1004 p.fType == XSParticleDecl.PARTICLE_WILDCARD) 1005 return p; 1006 1007 if (p.fMinOccurs==1 && p.fMaxOccurs==1 && 1008 p.fValue!=null && ((XSModelGroupImpl)p.fValue).fParticleCount == 1) 1009 return getNonUnaryGroup(((XSModelGroupImpl)p.fValue).fParticles[0]); 1010 else 1011 return p; 1012 } 1013 1014 private static Vector removePointlessChildren(XSParticleDecl p) { 1015 1016 if (p.fType == XSParticleDecl.PARTICLE_ELEMENT || 1017 p.fType == XSParticleDecl.PARTICLE_WILDCARD) 1018 return null; 1019 1020 Vector children = new Vector(); 1021 1022 XSModelGroupImpl group = (XSModelGroupImpl)p.fValue; 1023 for (int i = 0; i < group.fParticleCount; i++) 1024 gatherChildren(group.fCompositor, group.fParticles[i], children); 1025 1026 return children; 1027 } 1028 1029 1030 private static void gatherChildren(int parentType, XSParticleDecl p, Vector children) { 1031 1032 int min = p.fMinOccurs; 1033 int max = p.fMaxOccurs; 1034 int type = p.fType; 1035 if (type == XSParticleDecl.PARTICLE_MODELGROUP) 1036 type = ((XSModelGroupImpl)p.fValue).fCompositor; 1037 1038 if (type == XSParticleDecl.PARTICLE_ELEMENT || 1039 type== XSParticleDecl.PARTICLE_WILDCARD) { 1040 children.addElement(p); 1041 return; 1042 } 1043 1044 if (! (min==1 && max==1)) { 1045 children.addElement(p); 1046 } 1047 else if (parentType == type) { 1048 XSModelGroupImpl group = (XSModelGroupImpl)p.fValue; 1049 for (int i = 0; i < group.fParticleCount; i++) 1050 gatherChildren(type, group.fParticles[i], children); 1051 } 1052 else if (!p.isEmpty()) { 1053 children.addElement(p); 1054 } 1055 1056 } 1057 1058 private static void checkNameAndTypeOK(XSElementDecl dElement, int dMin, int dMax, 1059 XSElementDecl bElement, int bMin, int bMax) 1060 throws XMLSchemaException { 1061 1062 1063 // 1064 // Check that the names are the same 1065 // 1066 if (dElement.fName != bElement.fName || 1067 dElement.fTargetNamespace != bElement.fTargetNamespace) { 1068 throw new XMLSchemaException( 1069 "rcase-NameAndTypeOK.1",new Object[]{dElement.fName, 1070 dElement.fTargetNamespace, bElement.fName, bElement.fTargetNamespace}); 1071 } 1072 1073 // 1074 // Check nillable 1075 // 1076 if (!bElement.getNillable() && dElement.getNillable()) { 1077 throw new XMLSchemaException("rcase-NameAndTypeOK.2", 1078 new Object[]{dElement.fName}); 1079 } 1080 1081 // 1082 // Check occurrence range 1083 // 1084 if (!checkOccurrenceRange(dMin, dMax, bMin, bMax)) { 1085 throw new XMLSchemaException("rcase-NameAndTypeOK.3", 1086 new Object[]{ 1087 dElement.fName, 1088 Integer.toString(dMin), 1089 dMax==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(dMax), 1090 Integer.toString(bMin), 1091 bMax==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(bMax)}); 1092 } 1093 1094 // 1095 // Check for consistent fixed values 1096 // 1097 if (bElement.getConstraintType() == XSConstants.VC_FIXED) { 1098 // derived one has to have a fixed value 1099 if (dElement.getConstraintType() != XSConstants.VC_FIXED) { 1100 throw new XMLSchemaException("rcase-NameAndTypeOK.4.a", 1101 new Object[]{dElement.fName, bElement.fDefault.stringValue()}); 1102 } 1103 1104 // get simple type 1105 boolean isSimple = false; 1106 if (dElement.fType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE || 1107 ((XSComplexTypeDecl)dElement.fType).fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) { 1108 isSimple = true; 1109 } 1110 1111 // if there is no simple type, then compare based on string 1112 if (!isSimple && !bElement.fDefault.normalizedValue.equals(dElement.fDefault.normalizedValue) || 1113 isSimple && !bElement.fDefault.actualValue.equals(dElement.fDefault.actualValue)) { 1114 throw new XMLSchemaException("rcase-NameAndTypeOK.4.b", 1115 new Object[]{dElement.fName, 1116 dElement.fDefault.stringValue(), 1117 bElement.fDefault.stringValue()}); 1118 } 1119 } 1120 1121 // 1122 // Check identity constraints 1123 // 1124 checkIDConstraintRestriction(dElement, bElement); 1125 1126 // 1127 // Check for disallowed substitutions 1128 // 1129 int blockSet1 = dElement.fBlock; 1130 int blockSet2 = bElement.fBlock; 1131 if (((blockSet1 & blockSet2)!=blockSet2) || 1132 (blockSet1==XSConstants.DERIVATION_NONE && blockSet2!=XSConstants.DERIVATION_NONE)) 1133 throw new XMLSchemaException("rcase-NameAndTypeOK.6", 1134 new Object[]{dElement.fName}); 1135 1136 1137 // 1138 // Check that the derived element's type is derived from the base's. 1139 // 1140 if (!checkTypeDerivationOk(dElement.fType, bElement.fType, 1141 (short)(XSConstants.DERIVATION_EXTENSION|XSConstants.DERIVATION_LIST|XSConstants.DERIVATION_UNION))) { 1142 throw new XMLSchemaException("rcase-NameAndTypeOK.7", 1143 new Object[]{dElement.fName, dElement.fType.getName(), bElement.fType.getName()}); 1144 } 1145 1146 } 1147 1148 1149 private static void checkIDConstraintRestriction(XSElementDecl derivedElemDecl, 1150 XSElementDecl baseElemDecl) 1151 throws XMLSchemaException { 1152 // TODO 1153 } // checkIDConstraintRestriction 1154 1155 1156 private static boolean checkOccurrenceRange(int min1, int max1, int min2, int max2) { 1157 1158 if ((min1 >= min2) && 1159 ((max2==SchemaSymbols.OCCURRENCE_UNBOUNDED) || 1160 (max1!=SchemaSymbols.OCCURRENCE_UNBOUNDED && max1<=max2))) 1161 return true; 1162 else 1163 return false; 1164 } 1165 1166 private static void checkNSCompat(XSElementDecl elem, int min1, int max1, 1167 XSWildcardDecl wildcard, int min2, int max2, 1168 boolean checkWCOccurrence) 1169 throws XMLSchemaException { 1170 1171 // check Occurrence ranges 1172 if (checkWCOccurrence && !checkOccurrenceRange(min1,max1,min2,max2)) { 1173 throw new XMLSchemaException("rcase-NSCompat.2", 1174 new Object[]{ 1175 elem.fName, 1176 Integer.toString(min1), 1177 max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), 1178 Integer.toString(min2), 1179 max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); 1180 } 1181 1182 // check wildcard allows namespace of element 1183 if (!wildcard.allowNamespace(elem.fTargetNamespace)) { 1184 throw new XMLSchemaException("rcase-NSCompat.1", 1185 new Object[]{elem.fName,elem.fTargetNamespace}); 1186 } 1187 1188 } 1189 1190 private static void checkNSSubset(XSWildcardDecl dWildcard, int min1, int max1, 1191 XSWildcardDecl bWildcard, int min2, int max2) 1192 throws XMLSchemaException { 1193 1194 // check Occurrence ranges 1195 if (!checkOccurrenceRange(min1,max1,min2,max2)) { 1196 throw new XMLSchemaException("rcase-NSSubset.2", new Object[]{ 1197 Integer.toString(min1), 1198 max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), 1199 Integer.toString(min2), 1200 max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); 1201 } 1202 1203 // check wildcard subset 1204 if (!dWildcard.isSubsetOf(bWildcard)) { 1205 throw new XMLSchemaException("rcase-NSSubset.1", null); 1206 } 1207 1208 if (dWildcard.weakerProcessContents(bWildcard)) { 1209 throw new XMLSchemaException("rcase-NSSubset.3", 1210 new Object[]{dWildcard.getProcessContentsAsString(), 1211 bWildcard.getProcessContentsAsString()}); 1212 } 1213 1214 } 1215 1216 1217 private static void checkNSRecurseCheckCardinality(Vector children, int min1, int max1, 1218 SubstitutionGroupHandler dSGHandler, 1219 XSParticleDecl wildcard, int min2, int max2, 1220 boolean checkWCOccurrence) 1221 throws XMLSchemaException { 1222 1223 1224 // check Occurrence ranges 1225 if (checkWCOccurrence && !checkOccurrenceRange(min1,max1,min2,max2)) { 1226 throw new XMLSchemaException("rcase-NSRecurseCheckCardinality.2", new Object[]{ 1227 Integer.toString(min1), 1228 max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), 1229 Integer.toString(min2), 1230 max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); 1231 } 1232 1233 // Check that each member of the group is a valid restriction of the wildcard 1234 int count = children.size(); 1235 try { 1236 for (int i = 0; i < count; i++) { 1237 XSParticleDecl particle1 = (XSParticleDecl)children.elementAt(i); 1238 particleValidRestriction(particle1, dSGHandler, wildcard, null, false); 1239 1240 } 1241 } 1242 // REVISIT: should we really just ignore original cause of this error? 1243 // how can we report it? 1244 catch (XMLSchemaException e) { 1245 throw new XMLSchemaException("rcase-NSRecurseCheckCardinality.1", null); 1246 } 1247 1248 } 1249 1250 private static void checkRecurse(Vector dChildren, int min1, int max1, 1251 SubstitutionGroupHandler dSGHandler, 1252 Vector bChildren, int min2, int max2, 1253 SubstitutionGroupHandler bSGHandler) 1254 throws XMLSchemaException { 1255 1256 // check Occurrence ranges 1257 if (!checkOccurrenceRange(min1,max1,min2,max2)) { 1258 throw new XMLSchemaException("rcase-Recurse.1", new Object[]{ 1259 Integer.toString(min1), 1260 max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), 1261 Integer.toString(min2), 1262 max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); 1263 } 1264 1265 int count1= dChildren.size(); 1266 int count2= bChildren.size(); 1267 1268 int current = 0; 1269 label: for (int i = 0; i<count1; i++) { 1270 1271 XSParticleDecl particle1 = (XSParticleDecl)dChildren.elementAt(i); 1272 for (int j = current; j<count2; j++) { 1273 XSParticleDecl particle2 = (XSParticleDecl)bChildren.elementAt(j); 1274 current +=1; 1275 try { 1276 particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler); 1277 continue label; 1278 } 1279 catch (XMLSchemaException e) { 1280 if (!particle2.emptiable()) 1281 throw new XMLSchemaException("rcase-Recurse.2", null); 1282 } 1283 } 1284 throw new XMLSchemaException("rcase-Recurse.2", null); 1285 } 1286 1287 // Now, see if there are some elements in the base we didn't match up 1288 for (int j=current; j < count2; j++) { 1289 XSParticleDecl particle2 = (XSParticleDecl)bChildren.elementAt(j); 1290 if (!particle2.emptiable()) { 1291 throw new XMLSchemaException("rcase-Recurse.2", null); 1292 } 1293 } 1294 1295 } 1296 1297 private static void checkRecurseUnordered(Vector dChildren, int min1, int max1, 1298 SubstitutionGroupHandler dSGHandler, 1299 Vector bChildren, int min2, int max2, 1300 SubstitutionGroupHandler bSGHandler) 1301 throws XMLSchemaException { 1302 1303 1304 // check Occurrence ranges 1305 if (!checkOccurrenceRange(min1,max1,min2,max2)) { 1306 throw new XMLSchemaException("rcase-RecurseUnordered.1", new Object[]{ 1307 Integer.toString(min1), 1308 max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), 1309 Integer.toString(min2), 1310 max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); 1311 } 1312 1313 int count1= dChildren.size(); 1314 int count2 = bChildren.size(); 1315 1316 boolean foundIt[] = new boolean[count2]; 1317 1318 label: for (int i = 0; i<count1; i++) { 1319 XSParticleDecl particle1 = (XSParticleDecl)dChildren.elementAt(i); 1320 1321 for (int j = 0; j<count2; j++) { 1322 XSParticleDecl particle2 = (XSParticleDecl)bChildren.elementAt(j); 1323 try { 1324 particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler); 1325 if (foundIt[j]) 1326 throw new XMLSchemaException("rcase-RecurseUnordered.2", null); 1327 else 1328 foundIt[j]=true; 1329 1330 continue label; 1331 } 1332 catch (XMLSchemaException e) { 1333 } 1334 } 1335 // didn't find a match. Detect an error 1336 throw new XMLSchemaException("rcase-RecurseUnordered.2", null); 1337 } 1338 1339 // Now, see if there are some elements in the base we didn't match up 1340 for (int j=0; j < count2; j++) { 1341 XSParticleDecl particle2 = (XSParticleDecl)bChildren.elementAt(j); 1342 if (!foundIt[j] && !particle2.emptiable()) { 1343 throw new XMLSchemaException("rcase-RecurseUnordered.2", null); 1344 } 1345 } 1346 1347 } 1348 1349 private static void checkRecurseLax(Vector dChildren, int min1, int max1, 1350 SubstitutionGroupHandler dSGHandler, 1351 Vector bChildren, int min2, int max2, 1352 SubstitutionGroupHandler bSGHandler) 1353 throws XMLSchemaException { 1354 1355 // check Occurrence ranges 1356 if (!checkOccurrenceRange(min1,max1,min2,max2)) { 1357 throw new XMLSchemaException("rcase-RecurseLax.1", new Object[]{ 1358 Integer.toString(min1), 1359 max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), 1360 Integer.toString(min2), 1361 max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); 1362 } 1363 1364 int count1= dChildren.size(); 1365 int count2 = bChildren.size(); 1366 1367 int current = 0; 1368 label: for (int i = 0; i<count1; i++) { 1369 1370 XSParticleDecl particle1 = (XSParticleDecl)dChildren.elementAt(i); 1371 for (int j = current; j<count2; j++) { 1372 XSParticleDecl particle2 = (XSParticleDecl)bChildren.elementAt(j); 1373 current +=1; 1374 try { 1375 // IHR: go back one element on b list because the next element may match 1376 // this as well. 1377 if (particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler)) 1378 current--; 1379 continue label; 1380 } 1381 catch (XMLSchemaException e) { 1382 } 1383 } 1384 // didn't find a match. Detect an error 1385 throw new XMLSchemaException("rcase-RecurseLax.2", null); 1386 1387 } 1388 1389 } 1390 1391 private static void checkMapAndSum(Vector dChildren, int min1, int max1, 1392 SubstitutionGroupHandler dSGHandler, 1393 Vector bChildren, int min2, int max2, 1394 SubstitutionGroupHandler bSGHandler) 1395 throws XMLSchemaException { 1396 1397 // See if the sequence group is a valid restriction of the choice 1398 1399 // Here is an example of a valid restriction: 1400 // <choice minOccurs="2"> 1401 // <a/> 1402 // <b/> 1403 // <c/> 1404 // </choice> 1405 // 1406 // <sequence> 1407 // <b/> 1408 // <a/> 1409 // </sequence> 1410 1411 // check Occurrence ranges 1412 if (!checkOccurrenceRange(min1,max1,min2,max2)) { 1413 throw new XMLSchemaException("rcase-MapAndSum.2", 1414 new Object[]{Integer.toString(min1), 1415 max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1), 1416 Integer.toString(min2), 1417 max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)}); 1418 } 1419 1420 int count1 = dChildren.size(); 1421 int count2 = bChildren.size(); 1422 1423 label: for (int i = 0; i<count1; i++) { 1424 1425 XSParticleDecl particle1 = (XSParticleDecl)dChildren.elementAt(i); 1426 for (int j = 0; j<count2; j++) { 1427 XSParticleDecl particle2 = (XSParticleDecl)bChildren.elementAt(j); 1428 try { 1429 particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler); 1430 continue label; 1431 } 1432 catch (XMLSchemaException e) { 1433 } 1434 } 1435 // didn't find a match. Detect an error 1436 throw new XMLSchemaException("rcase-MapAndSum.1", null); 1437 } 1438 } 1439 // to check whether two element overlap, as defined in constraint UPA 1440 public static boolean overlapUPA(XSElementDecl element1, 1441 XSElementDecl element2, 1442 SubstitutionGroupHandler sgHandler) { 1443 // if the two element have the same name and namespace, 1444 if (element1.fName == element2.fName && 1445 element1.fTargetNamespace == element2.fTargetNamespace) { 1446 return true; 1447 } 1448 1449 // or if there is an element decl in element1's substitution group, 1450 // who has the same name/namespace with element2 1451 XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(element1); 1452 for (int i = subGroup.length-1; i >= 0; i--) { 1453 if (subGroup[i].fName == element2.fName && 1454 subGroup[i].fTargetNamespace == element2.fTargetNamespace) { 1455 return true; 1456 } 1457 } 1458 1459 // or if there is an element decl in element2's substitution group, 1460 // who has the same name/namespace with element1 1461 subGroup = sgHandler.getSubstitutionGroup(element2); 1462 for (int i = subGroup.length-1; i >= 0; i--) { 1463 if (subGroup[i].fName == element1.fName && 1464 subGroup[i].fTargetNamespace == element1.fTargetNamespace) { 1465 return true; 1466 } 1467 } 1468 1469 return false; 1470 } 1471 1472 // to check whether an element overlaps with a wildcard, 1473 // as defined in constraint UPA 1474 public static boolean overlapUPA(XSElementDecl element, 1475 XSWildcardDecl wildcard, 1476 SubstitutionGroupHandler sgHandler) { 1477 // if the wildcard allows the element 1478 if (wildcard.allowNamespace(element.fTargetNamespace)) 1479 return true; 1480 1481 // or if the wildcard allows any element in the substitution group 1482 XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(element); 1483 for (int i = subGroup.length-1; i >= 0; i--) { 1484 if (wildcard.allowNamespace(subGroup[i].fTargetNamespace)) 1485 return true; 1486 } 1487 1488 return false; 1489 } 1490 1491 public static boolean overlapUPA(XSWildcardDecl wildcard1, 1492 XSWildcardDecl wildcard2) { 1493 // if the intersection of the two wildcard is not empty list 1494 XSWildcardDecl intersect = wildcard1.performIntersectionWith(wildcard2, wildcard1.fProcessContents); 1495 if (intersect == null || 1496 intersect.fType != XSWildcardDecl.NSCONSTRAINT_LIST || 1497 intersect.fNamespaceList.length != 0) { 1498 return true; 1499 } 1500 1501 return false; 1502 } 1503 1504 // call one of the above methods according to the type of decls 1505 public static boolean overlapUPA(Object decl1, Object decl2, 1506 SubstitutionGroupHandler sgHandler) { 1507 if (decl1 instanceof XSElementDecl) { 1508 if (decl2 instanceof XSElementDecl) { 1509 return overlapUPA((XSElementDecl)decl1, 1510 (XSElementDecl)decl2, 1511 sgHandler); 1512 } 1513 else { 1514 return overlapUPA((XSElementDecl)decl1, 1515 (XSWildcardDecl)decl2, 1516 sgHandler); 1517 } 1518 } 1519 else { 1520 if (decl2 instanceof XSElementDecl) { 1521 return overlapUPA((XSElementDecl)decl2, 1522 (XSWildcardDecl)decl1, 1523 sgHandler); 1524 } 1525 else { 1526 return overlapUPA((XSWildcardDecl)decl1, 1527 (XSWildcardDecl)decl2); 1528 } 1529 } 1530 } 1531 1532 } // class XSContraints