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