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