1/* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 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 22package com.sun.org.apache.xerces.internal.impl.xs; 23 24import com.sun.org.apache.xerces.internal.impl.xs.util.StringListImpl; 25import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl; 26import com.sun.org.apache.xerces.internal.xs.StringList; 27import com.sun.org.apache.xerces.internal.xs.XSAnnotation; 28import com.sun.org.apache.xerces.internal.xs.XSConstants; 29import com.sun.org.apache.xerces.internal.xs.XSNamespaceItem; 30import com.sun.org.apache.xerces.internal.xs.XSWildcard; 31import com.sun.org.apache.xerces.internal.xs.XSObjectList; 32 33/** 34 * The XML representation for a wildcard declaration 35 * schema component is an <any> or <anyAttribute> element information item 36 * 37 * @xerces.internal 38 * 39 * @author Sandy Gao, IBM 40 * @author Rahul Srivastava, Sun Microsystems Inc. 41 * 42 */ 43public class XSWildcardDecl implements XSWildcard { 44 45 public static final String ABSENT = null; 46 47 // the type of wildcard: any, other, or list 48 public short fType = NSCONSTRAINT_ANY; 49 // the type of process contents: strict, lax, or skip 50 public short fProcessContents = PC_STRICT; 51 // the namespace list: 52 // for NSCONSTRAINT_LIST, it means one of the namespaces in the list 53 // for NSCONSTRAINT_NOT, it means not any of the namespaces in the list 54 public String[] fNamespaceList; 55 56 // optional annotation 57 public XSObjectList fAnnotations = null; 58 59 // I'm trying to implement the following constraint exactly as what the 60 // spec describes. Sometimes it seems redundant, and sometimes there seems 61 // to be much easier solutions. But it makes it easy to understand, 62 // easy to maintain, and easy to find a bug (either in the code, or in the 63 // spec). -SG 64 // 65 // NOTE: Schema spec only requires that ##other not(tNS,absent). 66 // The way we store ##other is not(NS1,NS2,...,NSN), which covers 67 // what's required by Schema, and allows future enhanced features. 68 // 69 // In the following in-line comments: 70 // - Bullet removed from w3c specification. 71 // + Bullet added as proposed by Sandy Gao, IBM. 72 // / Since we store ##other as not(NS1,NS2,...,NSN), we need to put some 73 // comments on where we didn't follow the spec exactly. 74 // * When we really support not(NS1,NS2,...,NSN), we need to revisit these items. 75 76 /** 77 * Validation Rule: Wildcard allows Namespace Name 78 */ 79 public boolean allowNamespace(String namespace) { 80 // For a value which is either a namespace name or absent to be valid with respect to a wildcard constraint (the value of a {namespace constraint}) one of the following must be true: 81 82 // 1 The constraint must be any. 83 if (fType == NSCONSTRAINT_ANY) 84 return true; 85 86 // 2 All of the following must be true: 87 // 2.1 The constraint is a pair of not and a namespace name or absent ([Definition:] call this the namespace test). 88 // 2.2 The value must not be identical to the namespace test. 89 // 2.3 The value must not be absent. 90 // / we store ##other as not(list), so our actual rule is 91 // / 2 The constraint is a pair of not and a set, and the value is not in such set. 92 if (fType == NSCONSTRAINT_NOT) { 93 boolean found = false; 94 int listNum = fNamespaceList.length; 95 for (int i = 0; i < listNum && !found; i++) { 96 if (namespace == fNamespaceList[i]) 97 found = true; 98 } 99 100 if (!found) 101 return true; 102 } 103 104 // 3 The constraint is a set, and the value is identical to one of the members of the set. 105 if (fType == NSCONSTRAINT_LIST) { 106 int listNum = fNamespaceList.length; 107 for (int i = 0; i < listNum; i++) { 108 if (namespace == fNamespaceList[i]) 109 return true; 110 } 111 } 112 113 // none of the above conditions applied, so return false. 114 return false; 115 } 116 117 /** 118 * Schema Component Constraint: Wildcard Subset 119 */ 120 public boolean isSubsetOf(XSWildcardDecl superWildcard) { 121 // if the super is null (not expressible), return false 122 if (superWildcard == null) 123 return false; 124 125 // For a namespace constraint (call it sub) to be an intensional subset of another 126 // namespace constraint (call it super) one of the following must be true: 127 128 // 1 super must be any. 129 if (superWildcard.fType == NSCONSTRAINT_ANY) { 130 return true; 131 } 132 133 // 2 All of the following must be true: 134 // 2.1 sub must be a pair of not and a namespace name or absent. 135 // 2.2 super must be a pair of not and the same value. 136 // * we can't just compare whether the namespace are the same value 137 // since we store other as not(list) 138 if (fType == NSCONSTRAINT_NOT) { 139 if (superWildcard.fType == NSCONSTRAINT_NOT && 140 fNamespaceList[0] == superWildcard.fNamespaceList[0]) { 141 return true; 142 } 143 } 144 145 // 3 All of the following must be true: 146 // 3.1 sub must be a set whose members are either namespace names or absent. 147 // 3.2 One of the following must be true: 148 // 3.2.1 super must be the same set or a superset thereof. 149 // -3.2.2 super must be a pair of not and a namespace name or absent and 150 // that value must not be in sub's set. 151 // +3.2.2 super must be a pair of not and a namespace name or absent and 152 // either that value or absent must not be in sub's set. 153 // * since we store ##other as not(list), we acturally need to make sure 154 // that none of the namespaces in super.list is in sub.list. 155 if (fType == NSCONSTRAINT_LIST) { 156 if (superWildcard.fType == NSCONSTRAINT_LIST && 157 subset2sets(fNamespaceList, superWildcard.fNamespaceList)) { 158 return true; 159 } 160 161 if (superWildcard.fType == NSCONSTRAINT_NOT && 162 !elementInSet(superWildcard.fNamespaceList[0], fNamespaceList) && 163 !elementInSet(ABSENT, fNamespaceList)) { 164 return true; 165 } 166 } 167 168 // none of the above conditions applied, so return false. 169 return false; 170 171 } // isSubsetOf 172 173 /** 174 * Check whether this wildcard has a weaker process contents than the super. 175 */ 176 public boolean weakerProcessContents(XSWildcardDecl superWildcard) { 177 return fProcessContents == XSWildcardDecl.PC_LAX && 178 superWildcard.fProcessContents == XSWildcardDecl.PC_STRICT || 179 fProcessContents == XSWildcardDecl.PC_SKIP && 180 superWildcard.fProcessContents != XSWildcardDecl.PC_SKIP; 181 } 182 183 /** 184 * Schema Component Constraint: Attribute Wildcard Union 185 */ 186 public XSWildcardDecl performUnionWith(XSWildcardDecl wildcard, 187 short processContents) { 188 // if the other wildcard is not expressible, the result is still not expressible 189 if (wildcard == null) 190 return null; 191 192 // For a wildcard's {namespace constraint} value to be the intensional union of two 193 // other such values (call them O1 and O2): the appropriate case among the following 194 // must be true: 195 196 XSWildcardDecl unionWildcard = new XSWildcardDecl(); 197 unionWildcard.fProcessContents = processContents; 198 199 // 1 If O1 and O2 are the same value, then that value must be the value. 200 if (areSame(wildcard)) { 201 unionWildcard.fType = fType; 202 unionWildcard.fNamespaceList = fNamespaceList; 203 } 204 205 // 2 If either O1 or O2 is any, then any must be the value. 206 else if ( (fType == NSCONSTRAINT_ANY) || (wildcard.fType == NSCONSTRAINT_ANY) ) { 207 unionWildcard.fType = NSCONSTRAINT_ANY; 208 } 209 210 // 3 If both O1 and O2 are sets of (namespace names or absent), then the union of 211 // those sets must be the value. 212 else if ( (fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_LIST) ) { 213 unionWildcard.fType = NSCONSTRAINT_LIST; 214 unionWildcard.fNamespaceList = union2sets(fNamespaceList, wildcard.fNamespaceList); 215 } 216 217 // -4 If the two are negations of different namespace names, then the intersection 218 // is not expressible. 219 // +4 If the two are negations of different namespace names or absent, then 220 // a pair of not and absent must be the value. 221 // * now we store ##other as not(list), the result should be 222 // not(intersection of two lists). 223 else if (fType == NSCONSTRAINT_NOT && wildcard.fType == NSCONSTRAINT_NOT) { 224 unionWildcard.fType = NSCONSTRAINT_NOT; 225 unionWildcard.fNamespaceList = new String[2]; 226 unionWildcard.fNamespaceList[0] = ABSENT; 227 unionWildcard.fNamespaceList[1] = ABSENT; 228 } 229 230 // 5 If either O1 or O2 is a pair of not and a namespace name and the other is a set of 231 // (namespace names or absent), then The appropriate case among the following must be true: 232 // -5.1 If the set includes the negated namespace name, then any must be the value. 233 // -5.2 If the set does not include the negated namespace name, then whichever of O1 or O2 234 // is a pair of not and a namespace name must be the value. 235 // +5.1 If the negated value is a namespace name, then The appropriate case 236 // among the following must be true: 237 // +5.1.1 If the set includes both the namespace name and absent, then any 238 // must be the value. 239 // +5.1.2 If the set includes the namespace name but does not include 240 // absent, then a pair of not and absent must be the value. 241 // +5.1.3 If the set does not include the namespace name but includes 242 // absent, then the union is not expressible. 243 // +5.1.4 If the set does not include either the namespace name or absent, 244 // then whichever of O1 or O2 is a pair of not and a namespace name must be 245 // the value. 246 // +5.2 If the negated value is absent, then The appropriate case among the 247 // following must be true: 248 // +5.2.1 If the set includes absent, then any must be the value. 249 // +5.2.2 If the set does not include absent, then whichever of O1 or O2 is 250 // a pair of not and a namespace name must be the value. 251 // * when we have not(list), the operation is just not(otherlist-list) 252 else if ( ((fType == NSCONSTRAINT_NOT) && (wildcard.fType == NSCONSTRAINT_LIST)) || 253 ((fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_NOT)) ) { 254 String[] other = null; 255 String[] list = null; 256 257 if (fType == NSCONSTRAINT_NOT) { 258 other = fNamespaceList; 259 list = wildcard.fNamespaceList; 260 } 261 else { 262 other = wildcard.fNamespaceList; 263 list = fNamespaceList; 264 } 265 266 boolean foundAbsent = elementInSet(ABSENT, list); 267 268 if (other[0] != ABSENT) { 269 boolean foundNS = elementInSet(other[0], list); 270 if (foundNS && foundAbsent) { 271 unionWildcard.fType = NSCONSTRAINT_ANY; 272 } else if (foundNS && !foundAbsent) { 273 unionWildcard.fType = NSCONSTRAINT_NOT; 274 unionWildcard.fNamespaceList = new String[2]; 275 unionWildcard.fNamespaceList[0] = ABSENT; 276 unionWildcard.fNamespaceList[1] = ABSENT; 277 } else if (!foundNS && foundAbsent) { 278 return null; 279 } else { // !foundNS && !foundAbsent 280 unionWildcard.fType = NSCONSTRAINT_NOT; 281 unionWildcard.fNamespaceList = other; 282 } 283 } else { // other[0] == ABSENT 284 if (foundAbsent) { 285 unionWildcard.fType = NSCONSTRAINT_ANY; 286 } else { // !foundAbsent 287 unionWildcard.fType = NSCONSTRAINT_NOT; 288 unionWildcard.fNamespaceList = other; 289 } 290 } 291 } 292 293 return unionWildcard; 294 295 } // performUnionWith 296 297 /** 298 * Schema Component Constraint: Attribute Wildcard Intersection 299 */ 300 public XSWildcardDecl performIntersectionWith(XSWildcardDecl wildcard, 301 short processContents) { 302 // if the other wildcard is not expressible, the result is still not expressible 303 if (wildcard == null) 304 return null; 305 306 // For a wildcard's {namespace constraint} value to be the intensional intersection of 307 // two other such values (call them O1 and O2): the appropriate case among the following 308 // must be true: 309 310 XSWildcardDecl intersectWildcard = new XSWildcardDecl(); 311 intersectWildcard.fProcessContents = processContents; 312 313 // 1 If O1 and O2 are the same value, then that value must be the value. 314 if (areSame(wildcard)) { 315 intersectWildcard.fType = fType; 316 intersectWildcard.fNamespaceList = fNamespaceList; 317 } 318 319 // 2 If either O1 or O2 is any, then the other must be the value. 320 else if ( (fType == NSCONSTRAINT_ANY) || (wildcard.fType == NSCONSTRAINT_ANY) ) { 321 // both cannot be ANY, if we have reached here. 322 XSWildcardDecl other = this; 323 324 if (fType == NSCONSTRAINT_ANY) 325 other = wildcard; 326 327 intersectWildcard.fType = other.fType; 328 intersectWildcard.fNamespaceList = other.fNamespaceList; 329 } 330 331 // -3 If either O1 or O2 is a pair of not and a namespace name and the other is a set of 332 // (namespace names or absent), then that set, minus the negated namespace name if 333 // it was in the set, must be the value. 334 // +3 If either O1 or O2 is a pair of not and a namespace name and the other 335 // is a set of (namespace names or absent), then that set, minus the negated 336 // namespace name if it was in the set, then minus absent if it was in the 337 // set, must be the value. 338 // * when we have not(list), the operation is just list-otherlist 339 else if ( ((fType == NSCONSTRAINT_NOT) && (wildcard.fType == NSCONSTRAINT_LIST)) || 340 ((fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_NOT)) ) { 341 String[] list = null; 342 String[] other = null; 343 344 if (fType == NSCONSTRAINT_NOT) { 345 other = fNamespaceList; 346 list = wildcard.fNamespaceList; 347 } 348 else { 349 other = wildcard.fNamespaceList; 350 list = fNamespaceList; 351 } 352 353 int listSize = list.length; 354 String[] intersect = new String[listSize]; 355 int newSize = 0; 356 for (int i = 0; i < listSize; i++) { 357 if (list[i] != other[0] && list[i] != ABSENT) 358 intersect[newSize++] = list[i]; 359 } 360 361 intersectWildcard.fType = NSCONSTRAINT_LIST; 362 intersectWildcard.fNamespaceList = new String[newSize]; 363 System.arraycopy(intersect, 0, intersectWildcard.fNamespaceList, 0, newSize); 364 } 365 366 // 4 If both O1 and O2 are sets of (namespace names or absent), then the intersection of those 367 // sets must be the value. 368 else if ( (fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_LIST) ) { 369 intersectWildcard.fType = NSCONSTRAINT_LIST; 370 intersectWildcard.fNamespaceList = intersect2sets(fNamespaceList, wildcard.fNamespaceList); 371 } 372 373 // -5 If the two are negations of different namespace names, then the intersection is not expressible. 374 // +5 If the two are negations of namespace names or absent, then The 375 // appropriate case among the following must be true: 376 // +5.1 If the two are negations of different namespace names, then the 377 // intersection is not expressible. 378 // +5.2 If one of the two is a pair of not and absent, the other must be 379 // the value. 380 // * when we have not(list), the operation is just not(onelist+otherlist) 381 else if (fType == NSCONSTRAINT_NOT && wildcard.fType == NSCONSTRAINT_NOT) { 382 if (fNamespaceList[0] != ABSENT && wildcard.fNamespaceList[0] != ABSENT) 383 return null; 384 385 XSWildcardDecl other = this; 386 if (fNamespaceList[0] == ABSENT) 387 other = wildcard; 388 389 intersectWildcard.fType = other.fType; 390 intersectWildcard.fNamespaceList = other.fNamespaceList; 391 } 392 393 return intersectWildcard; 394 395 } // performIntersectionWith 396 397 private boolean areSame(XSWildcardDecl wildcard) { 398 if (fType == wildcard.fType) { 399 // ##any, true 400 if (fType == NSCONSTRAINT_ANY) 401 return true; 402 403 // ##other, only check the negated value 404 // * when we support not(list), we need to check in the same way 405 // as for NSCONSTRAINT_LIST. 406 if (fType == NSCONSTRAINT_NOT) 407 return fNamespaceList[0] == wildcard.fNamespaceList[0]; 408 409 // ## list, must have the same length, 410 // and each item in one list must appear in the other one 411 // (we are assuming that there are no duplicate items in a list) 412 if (fNamespaceList.length == wildcard.fNamespaceList.length) { 413 for (int i=0; i<fNamespaceList.length; i++) { 414 if (!elementInSet(fNamespaceList[i], wildcard.fNamespaceList)) 415 return false; 416 } 417 return true; 418 } 419 } 420 421 return false; 422 } // areSame 423 424 String[] intersect2sets(String[] one, String[] theOther){ 425 String[] result = new String[Math.min(one.length,theOther.length)]; 426 427 // simple implemention, 428 int count = 0; 429 for (int i=0; i<one.length; i++) { 430 if (elementInSet(one[i], theOther)) 431 result[count++] = one[i]; 432 } 433 434 String[] result2 = new String[count]; 435 System.arraycopy(result, 0, result2, 0, count); 436 437 return result2; 438 } 439 440 String[] union2sets(String[] one, String[] theOther){ 441 String[] result1 = new String[one.length]; 442 443 // simple implemention, 444 int count = 0; 445 for (int i=0; i<one.length; i++) { 446 if (!elementInSet(one[i], theOther)) 447 result1[count++] = one[i]; 448 } 449 450 String[] result2 = new String[count+theOther.length]; 451 System.arraycopy(result1, 0, result2, 0, count); 452 System.arraycopy(theOther, 0, result2, count, theOther.length); 453 454 return result2; 455 } 456 457 boolean subset2sets(String[] subSet, String[] superSet){ 458 for (int i=0; i<subSet.length; i++) { 459 if (!elementInSet(subSet[i], superSet)) 460 return false; 461 } 462 463 return true; 464 } 465 466 boolean elementInSet(String ele, String[] set){ 467 boolean found = false; 468 for (int i=0; i<set.length && !found; i++) { 469 if (ele==set[i]) 470 found = true; 471 } 472 473 return found; 474 } 475 476 /** 477 * get the string description of this wildcard 478 */ 479 private String fDescription = null; 480 public String toString() { 481 if (fDescription == null) { 482 StringBuffer buffer = new StringBuffer(); 483 buffer.append("WC["); 484 switch (fType) { 485 case NSCONSTRAINT_ANY: 486 buffer.append(SchemaSymbols.ATTVAL_TWOPOUNDANY); 487 break; 488 case NSCONSTRAINT_NOT: 489 buffer.append(SchemaSymbols.ATTVAL_TWOPOUNDOTHER); 490 buffer.append(":\""); 491 if (fNamespaceList[0] != null) 492 buffer.append(fNamespaceList[0]); 493 buffer.append("\""); 494 break; 495 case NSCONSTRAINT_LIST: 496 if (fNamespaceList.length == 0) 497 break; 498 buffer.append("\""); 499 if (fNamespaceList[0] != null) 500 buffer.append(fNamespaceList[0]); 501 buffer.append("\""); 502 for (int i = 1; i < fNamespaceList.length; i++) { 503 buffer.append(",\""); 504 if (fNamespaceList[i] != null) 505 buffer.append(fNamespaceList[i]); 506 buffer.append("\""); 507 } 508 break; 509 } 510 buffer.append(']'); 511 fDescription = buffer.toString(); 512 } 513 514 return fDescription; 515 } 516 517 /** 518 * Get the type of the object, i.e ELEMENT_DECLARATION. 519 */ 520 public short getType() { 521 return XSConstants.WILDCARD; 522 } 523 524 /** 525 * The <code>name</code> of this <code>XSObject</code> depending on the 526 * <code>XSObject</code> type. 527 */ 528 public String getName() { 529 return null; 530 } 531 532 /** 533 * The namespace URI of this node, or <code>null</code> if it is 534 * unspecified. defines how a namespace URI is attached to schema 535 * components. 536 */ 537 public String getNamespace() { 538 return null; 539 } 540 541 /** 542 * Namespace constraint: A constraint type: any, not, list. 543 */ 544 public short getConstraintType() { 545 return fType; 546 } 547 548 /** 549 * Namespace constraint. For <code>constraintType</code> 550 * LIST_NSCONSTRAINT, the list contains allowed namespaces. For 551 * <code>constraintType</code> NOT_NSCONSTRAINT, the list contains 552 * disallowed namespaces. 553 */ 554 public StringList getNsConstraintList() { 555 return new StringListImpl(fNamespaceList, fNamespaceList == null ? 0 : fNamespaceList.length); 556 } 557 558 /** 559 * {process contents} One of skip, lax or strict. Valid constants values 560 * are: PC_SKIP, PC_LAX, PC_STRICT. 561 */ 562 public short getProcessContents() { 563 return fProcessContents; 564 } 565 566 /** 567 * String valid of {process contents}. One of "skip", "lax" or "strict". 568 */ 569 public String getProcessContentsAsString() { 570 switch (fProcessContents) { 571 case XSWildcardDecl.PC_SKIP: return "skip"; 572 case XSWildcardDecl.PC_LAX: return "lax"; 573 case XSWildcardDecl.PC_STRICT: return "strict"; 574 default: return "invalid value"; 575 } 576 } 577 578 /** 579 * Optional. Annotation. 580 */ 581 public XSAnnotation getAnnotation() { 582 return (fAnnotations != null) ? (XSAnnotation) fAnnotations.item(0) : null; 583 } 584 585 /** 586 * Optional. Annotations. 587 */ 588 public XSObjectList getAnnotations() { 589 return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST; 590 } 591 592 /** 593 * @see org.apache.xerces.xs.XSObject#getNamespaceItem() 594 */ 595 public XSNamespaceItem getNamespaceItem() { 596 return null; 597 } 598 599} // class XSWildcardDecl 600