001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.xerces.impl.xs;
019:
020: import org.apache.xerces.xs.StringList;
021: import org.apache.xerces.xs.XSAnnotation;
022: import org.apache.xerces.xs.XSConstants;
023: import org.apache.xerces.xs.XSNamespaceItem;
024: import org.apache.xerces.xs.XSObjectList;
025: import org.apache.xerces.xs.XSWildcard;
026: import org.apache.xerces.impl.xs.util.StringListImpl;
027: import org.apache.xerces.impl.xs.util.XSObjectListImpl;
028:
029: /**
030: * The XML representation for a wildcard declaration
031: * schema component is an <any> or <anyAttribute> element information item
032: *
033: * @xerces.internal
034: *
035: * @author Sandy Gao, IBM
036: * @author Rahul Srivastava, Sun Microsystems Inc.
037: *
038: * @version $Id: XSWildcardDecl.java 449424 2006-09-24 16:22:30Z mrglavas $
039: */
040: public class XSWildcardDecl implements XSWildcard {
041:
042: public static final String ABSENT = null;
043:
044: // the type of wildcard: any, other, or list
045: public short fType = NSCONSTRAINT_ANY;
046: // the type of process contents: strict, lax, or skip
047: public short fProcessContents = PC_STRICT;
048: // the namespace list:
049: // for NSCONSTRAINT_LIST, it means one of the namespaces in the list
050: // for NSCONSTRAINT_NOT, it means not any of the namespaces in the list
051: public String[] fNamespaceList;
052:
053: // optional annotation
054: public XSObjectList fAnnotations = null;
055:
056: // I'm trying to implement the following constraint exactly as what the
057: // spec describes. Sometimes it seems redundant, and sometimes there seems
058: // to be much easier solutions. But it makes it easy to understand,
059: // easy to maintain, and easy to find a bug (either in the code, or in the
060: // spec). -SG
061: //
062: // NOTE: Schema spec only requires that ##other not(tNS,absent).
063: // The way we store ##other is not(NS1,NS2,...,NSN), which covers
064: // what's required by Schema, and allows future enhanced features.
065: //
066: // In the following in-line comments:
067: // - Bullet removed from w3c specification.
068: // + Bullet added as proposed by Sandy Gao, IBM.
069: // / Since we store ##other as not(NS1,NS2,...,NSN), we need to put some
070: // comments on where we didn't follow the spec exactly.
071: // * When we really support not(NS1,NS2,...,NSN), we need to revisit these items.
072:
073: /**
074: * Validation Rule: Wildcard allows Namespace Name
075: */
076: public boolean allowNamespace(String namespace) {
077: // 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:
078:
079: // 1 The constraint must be any.
080: if (fType == NSCONSTRAINT_ANY)
081: return true;
082:
083: // 2 All of the following must be true:
084: // 2.1 The constraint is a pair of not and a namespace name or absent ([Definition:] call this the namespace test).
085: // 2.2 The value must not be identical to the namespace test.
086: // 2.3 The value must not be absent.
087: // / we store ##other as not(list), so our actual rule is
088: // / 2 The constraint is a pair of not and a set, and the value is not in such set.
089: if (fType == NSCONSTRAINT_NOT) {
090: boolean found = false;
091: int listNum = fNamespaceList.length;
092: for (int i = 0; i < listNum && !found; i++) {
093: if (namespace == fNamespaceList[i])
094: found = true;
095: }
096:
097: if (!found)
098: return true;
099: }
100:
101: // 3 The constraint is a set, and the value is identical to one of the members of the set.
102: if (fType == NSCONSTRAINT_LIST) {
103: int listNum = fNamespaceList.length;
104: for (int i = 0; i < listNum; i++) {
105: if (namespace == fNamespaceList[i])
106: return true;
107: }
108: }
109:
110: // none of the above conditions applied, so return false.
111: return false;
112: }
113:
114: /**
115: * Schema Component Constraint: Wildcard Subset
116: */
117: public boolean isSubsetOf(XSWildcardDecl super Wildcard) {
118: // if the super is null (not expressible), return false
119: if (super Wildcard == null)
120: return false;
121:
122: // For a namespace constraint (call it sub) to be an intensional subset of another
123: // namespace constraint (call it super) one of the following must be true:
124:
125: // 1 super must be any.
126: if (super Wildcard.fType == NSCONSTRAINT_ANY) {
127: return true;
128: }
129:
130: // 2 All of the following must be true:
131: // 2.1 sub must be a pair of not and a namespace name or absent.
132: // 2.2 super must be a pair of not and the same value.
133: // * we can't just compare whether the namespace are the same value
134: // since we store other as not(list)
135: if (fType == NSCONSTRAINT_NOT) {
136: if (super Wildcard.fType == NSCONSTRAINT_NOT
137: && fNamespaceList[0] == super Wildcard.fNamespaceList[0]) {
138: return true;
139: }
140: }
141:
142: // 3 All of the following must be true:
143: // 3.1 sub must be a set whose members are either namespace names or absent.
144: // 3.2 One of the following must be true:
145: // 3.2.1 super must be the same set or a superset thereof.
146: // -3.2.2 super must be a pair of not and a namespace name or absent and
147: // that value must not be in sub's set.
148: // +3.2.2 super must be a pair of not and a namespace name or absent and
149: // either that value or absent must not be in sub's set.
150: // * since we store ##other as not(list), we acturally need to make sure
151: // that none of the namespaces in super.list is in sub.list.
152: if (fType == NSCONSTRAINT_LIST) {
153: if (super Wildcard.fType == NSCONSTRAINT_LIST
154: && subset2sets(fNamespaceList,
155: super Wildcard.fNamespaceList)) {
156: return true;
157: }
158:
159: if (super Wildcard.fType == NSCONSTRAINT_NOT
160: && !elementInSet(super Wildcard.fNamespaceList[0],
161: 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 super Wildcard) {
176: return fProcessContents == XSWildcardDecl.PC_LAX
177: && super Wildcard.fProcessContents == XSWildcardDecl.PC_STRICT
178: || fProcessContents == XSWildcardDecl.PC_SKIP
179: && super Wildcard.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)
206: || (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)
213: && (wildcard.fType == NSCONSTRAINT_LIST)) {
214: unionWildcard.fType = NSCONSTRAINT_LIST;
215: unionWildcard.fNamespaceList = union2sets(fNamespaceList,
216: wildcard.fNamespaceList);
217: }
218:
219: // -4 If the two are negations of different namespace names, then the intersection
220: // is not expressible.
221: // +4 If the two are negations of different namespace names or absent, then
222: // a pair of not and absent must be the value.
223: // * now we store ##other as not(list), the result should be
224: // not(intersection of two lists).
225: else if (fType == NSCONSTRAINT_NOT
226: && wildcard.fType == NSCONSTRAINT_NOT) {
227: unionWildcard.fType = NSCONSTRAINT_NOT;
228: unionWildcard.fNamespaceList = new String[2];
229: unionWildcard.fNamespaceList[0] = ABSENT;
230: unionWildcard.fNamespaceList[1] = ABSENT;
231: }
232:
233: // 5 If either O1 or O2 is a pair of not and a namespace name and the other is a set of
234: // (namespace names or absent), then The appropriate case among the following must be true:
235: // -5.1 If the set includes the negated namespace name, then any must be the value.
236: // -5.2 If the set does not include the negated namespace name, then whichever of O1 or O2
237: // is a pair of not and a namespace name must be the value.
238: // +5.1 If the negated value is a namespace name, then The appropriate case
239: // among the following must be true:
240: // +5.1.1 If the set includes both the namespace name and absent, then any
241: // must be the value.
242: // +5.1.2 If the set includes the namespace name but does not include
243: // absent, then a pair of not and absent must be the value.
244: // +5.1.3 If the set does not include the namespace name but includes
245: // absent, then the union is not expressible.
246: // +5.1.4 If the set does not include either the namespace name or absent,
247: // then whichever of O1 or O2 is a pair of not and a namespace name must be
248: // the value.
249: // +5.2 If the negated value is absent, then The appropriate case among the
250: // following must be true:
251: // +5.2.1 If the set includes absent, then any must be the value.
252: // +5.2.2 If the set does not include absent, then whichever of O1 or O2 is
253: // a pair of not and a namespace name must be the value.
254: // * when we have not(list), the operation is just not(otherlist-list)
255: else if (((fType == NSCONSTRAINT_NOT) && (wildcard.fType == NSCONSTRAINT_LIST))
256: || ((fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_NOT))) {
257: String[] other = null;
258: String[] list = null;
259:
260: if (fType == NSCONSTRAINT_NOT) {
261: other = fNamespaceList;
262: list = wildcard.fNamespaceList;
263: } else {
264: other = wildcard.fNamespaceList;
265: list = fNamespaceList;
266: }
267:
268: boolean foundAbsent = elementInSet(ABSENT, list);
269:
270: if (other[0] != ABSENT) {
271: boolean foundNS = elementInSet(other[0], list);
272: if (foundNS && foundAbsent) {
273: unionWildcard.fType = NSCONSTRAINT_ANY;
274: } else if (foundNS && !foundAbsent) {
275: unionWildcard.fType = NSCONSTRAINT_NOT;
276: unionWildcard.fNamespaceList = new String[2];
277: unionWildcard.fNamespaceList[0] = ABSENT;
278: unionWildcard.fNamespaceList[1] = ABSENT;
279: } else if (!foundNS && foundAbsent) {
280: return null;
281: } else { // !foundNS && !foundAbsent
282: unionWildcard.fType = NSCONSTRAINT_NOT;
283: unionWildcard.fNamespaceList = other;
284: }
285: } else { // other[0] == ABSENT
286: if (foundAbsent) {
287: unionWildcard.fType = NSCONSTRAINT_ANY;
288: } else { // !foundAbsent
289: unionWildcard.fType = NSCONSTRAINT_NOT;
290: unionWildcard.fNamespaceList = other;
291: }
292: }
293: }
294:
295: return unionWildcard;
296:
297: } // performUnionWith
298:
299: /**
300: * Schema Component Constraint: Attribute Wildcard Intersection
301: */
302: public XSWildcardDecl performIntersectionWith(
303: XSWildcardDecl wildcard, short processContents) {
304: // if the other wildcard is not expressible, the result is still not expressible
305: if (wildcard == null)
306: return null;
307:
308: // For a wildcard's {namespace constraint} value to be the intensional intersection of
309: // two other such values (call them O1 and O2): the appropriate case among the following
310: // must be true:
311:
312: XSWildcardDecl intersectWildcard = new XSWildcardDecl();
313: intersectWildcard.fProcessContents = processContents;
314:
315: // 1 If O1 and O2 are the same value, then that value must be the value.
316: if (areSame(wildcard)) {
317: intersectWildcard.fType = fType;
318: intersectWildcard.fNamespaceList = fNamespaceList;
319: }
320:
321: // 2 If either O1 or O2 is any, then the other must be the value.
322: else if ((fType == NSCONSTRAINT_ANY)
323: || (wildcard.fType == NSCONSTRAINT_ANY)) {
324: // both cannot be ANY, if we have reached here.
325: XSWildcardDecl other = this ;
326:
327: if (fType == NSCONSTRAINT_ANY)
328: other = wildcard;
329:
330: intersectWildcard.fType = other.fType;
331: intersectWildcard.fNamespaceList = other.fNamespaceList;
332: }
333:
334: // -3 If either O1 or O2 is a pair of not and a namespace name and the other is a set of
335: // (namespace names or absent), then that set, minus the negated namespace name if
336: // it was in the set, must be the value.
337: // +3 If either O1 or O2 is a pair of not and a namespace name and the other
338: // is a set of (namespace names or absent), then that set, minus the negated
339: // namespace name if it was in the set, then minus absent if it was in the
340: // set, must be the value.
341: // * when we have not(list), the operation is just list-otherlist
342: else if (((fType == NSCONSTRAINT_NOT) && (wildcard.fType == NSCONSTRAINT_LIST))
343: || ((fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_NOT))) {
344: String[] list = null;
345: String[] other = null;
346:
347: if (fType == NSCONSTRAINT_NOT) {
348: other = fNamespaceList;
349: list = wildcard.fNamespaceList;
350: } else {
351: other = wildcard.fNamespaceList;
352: list = fNamespaceList;
353: }
354:
355: int listSize = list.length;
356: String[] intersect = new String[listSize];
357: int newSize = 0;
358: for (int i = 0; i < listSize; i++) {
359: if (list[i] != other[0] && list[i] != ABSENT)
360: intersect[newSize++] = list[i];
361: }
362:
363: intersectWildcard.fType = NSCONSTRAINT_LIST;
364: intersectWildcard.fNamespaceList = new String[newSize];
365: System.arraycopy(intersect, 0,
366: intersectWildcard.fNamespaceList, 0, newSize);
367: }
368:
369: // 4 If both O1 and O2 are sets of (namespace names or absent), then the intersection of those
370: // sets must be the value.
371: else if ((fType == NSCONSTRAINT_LIST)
372: && (wildcard.fType == NSCONSTRAINT_LIST)) {
373: intersectWildcard.fType = NSCONSTRAINT_LIST;
374: intersectWildcard.fNamespaceList = intersect2sets(
375: fNamespaceList, wildcard.fNamespaceList);
376: }
377:
378: // -5 If the two are negations of different namespace names, then the intersection is not expressible.
379: // +5 If the two are negations of namespace names or absent, then The
380: // appropriate case among the following must be true:
381: // +5.1 If the two are negations of different namespace names, then the
382: // intersection is not expressible.
383: // +5.2 If one of the two is a pair of not and absent, the other must be
384: // the value.
385: // * when we have not(list), the operation is just not(onelist+otherlist)
386: else if (fType == NSCONSTRAINT_NOT
387: && wildcard.fType == NSCONSTRAINT_NOT) {
388: if (fNamespaceList[0] != ABSENT
389: && wildcard.fNamespaceList[0] != ABSENT)
390: return null;
391:
392: XSWildcardDecl other = this ;
393: if (fNamespaceList[0] == ABSENT)
394: other = wildcard;
395:
396: intersectWildcard.fType = other.fType;
397: intersectWildcard.fNamespaceList = other.fNamespaceList;
398: }
399:
400: return intersectWildcard;
401:
402: } // performIntersectionWith
403:
404: private boolean areSame(XSWildcardDecl wildcard) {
405: if (fType == wildcard.fType) {
406: // ##any, true
407: if (fType == NSCONSTRAINT_ANY)
408: return true;
409:
410: // ##other, only check the negated value
411: // * when we support not(list), we need to check in the same way
412: // as for NSCONSTRAINT_LIST.
413: if (fType == NSCONSTRAINT_NOT)
414: return fNamespaceList[0] == wildcard.fNamespaceList[0];
415:
416: // ## list, must have the same length,
417: // and each item in one list must appear in the other one
418: // (we are assuming that there are no duplicate items in a list)
419: if (fNamespaceList.length == wildcard.fNamespaceList.length) {
420: for (int i = 0; i < fNamespaceList.length; i++) {
421: if (!elementInSet(fNamespaceList[i],
422: wildcard.fNamespaceList))
423: return false;
424: }
425: return true;
426: }
427: }
428:
429: return false;
430: } // areSame
431:
432: String[] intersect2sets(String[] one, String[] theOther) {
433: String[] result = new String[Math.min(one.length,
434: theOther.length)];
435:
436: // simple implemention,
437: int count = 0;
438: for (int i = 0; i < one.length; i++) {
439: if (elementInSet(one[i], theOther))
440: result[count++] = one[i];
441: }
442:
443: String[] result2 = new String[count];
444: System.arraycopy(result, 0, result2, 0, count);
445:
446: return result2;
447: }
448:
449: String[] union2sets(String[] one, String[] theOther) {
450: String[] result1 = new String[one.length];
451:
452: // simple implemention,
453: int count = 0;
454: for (int i = 0; i < one.length; i++) {
455: if (!elementInSet(one[i], theOther))
456: result1[count++] = one[i];
457: }
458:
459: String[] result2 = new String[count + theOther.length];
460: System.arraycopy(result1, 0, result2, 0, count);
461: System.arraycopy(theOther, 0, result2, count, theOther.length);
462:
463: return result2;
464: }
465:
466: boolean subset2sets(String[] subSet, String[] super Set) {
467: for (int i = 0; i < subSet.length; i++) {
468: if (!elementInSet(subSet[i], super Set))
469: return false;
470: }
471:
472: return true;
473: }
474:
475: boolean elementInSet(String ele, String[] set) {
476: boolean found = false;
477: for (int i = 0; i < set.length && !found; i++) {
478: if (ele == set[i])
479: found = true;
480: }
481:
482: return found;
483: }
484:
485: /**
486: * get the string description of this wildcard
487: */
488: private String fDescription = null;
489:
490: public String toString() {
491: if (fDescription == null) {
492: StringBuffer buffer = new StringBuffer();
493: buffer.append("WC[");
494: switch (fType) {
495: case NSCONSTRAINT_ANY:
496: buffer.append(SchemaSymbols.ATTVAL_TWOPOUNDANY);
497: break;
498: case NSCONSTRAINT_NOT:
499: buffer.append(SchemaSymbols.ATTVAL_TWOPOUNDOTHER);
500: buffer.append(":\"");
501: if (fNamespaceList[0] != null)
502: buffer.append(fNamespaceList[0]);
503: buffer.append("\"");
504: break;
505: case NSCONSTRAINT_LIST:
506: if (fNamespaceList.length == 0)
507: break;
508: buffer.append("\"");
509: if (fNamespaceList[0] != null)
510: buffer.append(fNamespaceList[0]);
511: buffer.append("\"");
512: for (int i = 1; i < fNamespaceList.length; i++) {
513: buffer.append(",\"");
514: if (fNamespaceList[i] != null)
515: buffer.append(fNamespaceList[i]);
516: buffer.append("\"");
517: }
518: break;
519: }
520: buffer.append("]");
521: fDescription = buffer.toString();
522: }
523:
524: return fDescription;
525: }
526:
527: /**
528: * Get the type of the object, i.e ELEMENT_DECLARATION.
529: */
530: public short getType() {
531: return XSConstants.WILDCARD;
532: }
533:
534: /**
535: * The <code>name</code> of this <code>XSObject</code> depending on the
536: * <code>XSObject</code> type.
537: */
538: public String getName() {
539: return null;
540: }
541:
542: /**
543: * The namespace URI of this node, or <code>null</code> if it is
544: * unspecified. defines how a namespace URI is attached to schema
545: * components.
546: */
547: public String getNamespace() {
548: return null;
549: }
550:
551: /**
552: * Namespace constraint: A constraint type: any, not, list.
553: */
554: public short getConstraintType() {
555: return fType;
556: }
557:
558: /**
559: * Namespace constraint. For <code>constraintType</code>
560: * LIST_NSCONSTRAINT, the list contains allowed namespaces. For
561: * <code>constraintType</code> NOT_NSCONSTRAINT, the list contains
562: * disallowed namespaces.
563: */
564: public StringList getNsConstraintList() {
565: return new StringListImpl(fNamespaceList,
566: fNamespaceList == null ? 0 : fNamespaceList.length);
567: }
568:
569: /**
570: * {process contents} One of skip, lax or strict. Valid constants values
571: * are: PC_SKIP, PC_LAX, PC_STRICT.
572: */
573: public short getProcessContents() {
574: return fProcessContents;
575: }
576:
577: /**
578: * String valid of {process contents}. One of "skip", "lax" or "strict".
579: */
580: public String getProcessContentsAsString() {
581: switch (fProcessContents) {
582: case XSWildcardDecl.PC_SKIP:
583: return "skip";
584: case XSWildcardDecl.PC_LAX:
585: return "lax";
586: case XSWildcardDecl.PC_STRICT:
587: return "strict";
588: default:
589: return "invalid value";
590: }
591: }
592:
593: /**
594: * Optional. Annotation.
595: */
596: public XSAnnotation getAnnotation() {
597: return (fAnnotations != null) ? (XSAnnotation) fAnnotations
598: .item(0) : null;
599: }
600:
601: /**
602: * Optional. Annotations.
603: */
604: public XSObjectList getAnnotations() {
605: return (fAnnotations != null) ? fAnnotations
606: : XSObjectListImpl.EMPTY_LIST;
607: }
608:
609: /**
610: * @see org.apache.xerces.xs.XSObject#getNamespaceItem()
611: */
612: public XSNamespaceItem getNamespaceItem() {
613: // REVISIT: implement
614: return null;
615: }
616:
617: } // class XSWildcardDecl
|