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