|
|
|
|
|
|
|
*/ |
|
/* |
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
|
* contributor license agreements. See the NOTICE file distributed with |
|
* this work for additional information regarding copyright ownership. |
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
* (the "License"); you may not use this file except in compliance with |
|
* the License. You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
package com.sun.org.apache.xerces.internal.impl.xs; |
|
|
|
import com.sun.org.apache.xerces.internal.impl.xs.util.StringListImpl; |
|
import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl; |
|
import com.sun.org.apache.xerces.internal.xs.StringList; |
|
import com.sun.org.apache.xerces.internal.xs.XSAnnotation; |
|
import com.sun.org.apache.xerces.internal.xs.XSConstants; |
|
import com.sun.org.apache.xerces.internal.xs.XSNamespaceItem; |
|
import com.sun.org.apache.xerces.internal.xs.XSWildcard; |
|
import com.sun.org.apache.xerces.internal.xs.XSObjectList; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class XSWildcardDecl implements XSWildcard { |
|
|
|
public static final String ABSENT = null; |
|
|
|
|
|
public short fType = NSCONSTRAINT_ANY; |
|
|
|
public short fProcessContents = PC_STRICT; |
|
// the namespace list: |
|
// for NSCONSTRAINT_LIST, it means one of the namespaces in the list |
|
|
|
public String[] fNamespaceList; |
|
|
|
|
|
public XSObjectList fAnnotations = null; |
|
|
|
// I'm trying to implement the following constraint exactly as what the |
|
// spec describes. Sometimes it seems redundant, and sometimes there seems |
|
// to be much easier solutions. But it makes it easy to understand, |
|
// easy to maintain, and easy to find a bug (either in the code, or in the |
|
// spec). -SG |
|
// |
|
// NOTE: Schema spec only requires that ##other not(tNS,absent). |
|
// The way we store ##other is not(NS1,NS2,...,NSN), which covers |
|
// what's required by Schema, and allows future enhanced features. |
|
// |
|
// In the following in-line comments: |
|
// - Bullet removed from w3c specification. |
|
// + Bullet added as proposed by Sandy Gao, IBM. |
|
// / Since we store ##other as not(NS1,NS2,...,NSN), we need to put some |
|
// comments on where we didn't follow the spec exactly. |
|
// * When we really support not(NS1,NS2,...,NSN), we need to revisit these items. |
|
|
|
|
|
|
|
*/ |
|
public boolean allowNamespace(String namespace) { |
|
// 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: |
|
|
|
|
|
if (fType == NSCONSTRAINT_ANY) |
|
return true; |
|
|
|
// 2 All of the following must be true: |
|
// 2.1 The constraint is a pair of not and a namespace name or absent ([Definition:] call this the namespace test). |
|
// 2.2 The value must not be identical to the namespace test. |
|
// 2.3 The value must not be absent. |
|
// / we store ##other as not(list), so our actual rule is |
|
|
|
if (fType == NSCONSTRAINT_NOT) { |
|
boolean found = false; |
|
int listNum = fNamespaceList.length; |
|
for (int i = 0; i < listNum && !found; i++) { |
|
if (namespace == fNamespaceList[i]) |
|
found = true; |
|
} |
|
|
|
if (!found) |
|
return true; |
|
} |
|
|
|
|
|
if (fType == NSCONSTRAINT_LIST) { |
|
int listNum = fNamespaceList.length; |
|
for (int i = 0; i < listNum; i++) { |
|
if (namespace == fNamespaceList[i]) |
|
return true; |
|
} |
|
} |
|
|
|
|
|
return false; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public boolean isSubsetOf(XSWildcardDecl superWildcard) { |
|
|
|
if (superWildcard == null) |
|
return false; |
|
|
|
// For a namespace constraint (call it sub) to be an intensional subset of another |
|
// namespace constraint (call it super) one of the following must be true: |
|
|
|
|
|
if (superWildcard.fType == NSCONSTRAINT_ANY) { |
|
return true; |
|
} |
|
|
|
// 2 All of the following must be true: |
|
// 2.1 sub must be a pair of not and a namespace name or absent. |
|
// 2.2 super must be a pair of not and the same value. |
|
// * we can't just compare whether the namespace are the same value |
|
|
|
if (fType == NSCONSTRAINT_NOT) { |
|
if (superWildcard.fType == NSCONSTRAINT_NOT && |
|
fNamespaceList[0] == superWildcard.fNamespaceList[0]) { |
|
return true; |
|
} |
|
} |
|
|
|
// 3 All of the following must be true: |
|
// 3.1 sub must be a set whose members are either namespace names or absent. |
|
// 3.2 One of the following must be true: |
|
// 3.2.1 super must be the same set or a superset thereof. |
|
// -3.2.2 super must be a pair of not and a namespace name or absent and |
|
// that value must not be in sub's set. |
|
// +3.2.2 super must be a pair of not and a namespace name or absent and |
|
// either that value or absent must not be in sub's set. |
|
// * since we store ##other as not(list), we acturally need to make sure |
|
|
|
if (fType == NSCONSTRAINT_LIST) { |
|
if (superWildcard.fType == NSCONSTRAINT_LIST && |
|
subset2sets(fNamespaceList, superWildcard.fNamespaceList)) { |
|
return true; |
|
} |
|
|
|
if (superWildcard.fType == NSCONSTRAINT_NOT && |
|
!elementInSet(superWildcard.fNamespaceList[0], fNamespaceList) && |
|
!elementInSet(ABSENT, fNamespaceList)) { |
|
return true; |
|
} |
|
} |
|
|
|
|
|
return false; |
|
|
|
} // isSubsetOf |
|
|
|
|
|
|
|
*/ |
|
public boolean weakerProcessContents(XSWildcardDecl superWildcard) { |
|
return fProcessContents == XSWildcardDecl.PC_LAX && |
|
superWildcard.fProcessContents == XSWildcardDecl.PC_STRICT || |
|
fProcessContents == XSWildcardDecl.PC_SKIP && |
|
superWildcard.fProcessContents != XSWildcardDecl.PC_SKIP; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public XSWildcardDecl performUnionWith(XSWildcardDecl wildcard, |
|
short processContents) { |
|
|
|
if (wildcard == null) |
|
return null; |
|
|
|
// For a wildcard's {namespace constraint} value to be the intensional union of two |
|
// other such values (call them O1 and O2): the appropriate case among the following |
|
// must be true: |
|
|
|
XSWildcardDecl unionWildcard = new XSWildcardDecl(); |
|
unionWildcard.fProcessContents = processContents; |
|
|
|
|
|
if (areSame(wildcard)) { |
|
unionWildcard.fType = fType; |
|
unionWildcard.fNamespaceList = fNamespaceList; |
|
} |
|
|
|
|
|
else if ( (fType == NSCONSTRAINT_ANY) || (wildcard.fType == NSCONSTRAINT_ANY) ) { |
|
unionWildcard.fType = NSCONSTRAINT_ANY; |
|
} |
|
|
|
// 3 If both O1 and O2 are sets of (namespace names or absent), then the union of |
|
|
|
else if ( (fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_LIST) ) { |
|
unionWildcard.fType = NSCONSTRAINT_LIST; |
|
unionWildcard.fNamespaceList = union2sets(fNamespaceList, wildcard.fNamespaceList); |
|
} |
|
|
|
// -4 If the two are negations of different namespace names, then the intersection |
|
// is not expressible. |
|
// +4 If the two are negations of different namespace names or absent, then |
|
// a pair of not and absent must be the value. |
|
// * now we store ##other as not(list), the result should be |
|
|
|
else if (fType == NSCONSTRAINT_NOT && wildcard.fType == NSCONSTRAINT_NOT) { |
|
unionWildcard.fType = NSCONSTRAINT_NOT; |
|
unionWildcard.fNamespaceList = new String[2]; |
|
unionWildcard.fNamespaceList[0] = ABSENT; |
|
unionWildcard.fNamespaceList[1] = ABSENT; |
|
} |
|
|
|
// 5 If either O1 or O2 is a pair of not and a namespace name and the other is a set of |
|
// (namespace names or absent), then The appropriate case among the following must be true: |
|
// -5.1 If the set includes the negated namespace name, then any must be the value. |
|
// -5.2 If the set does not include the negated namespace name, then whichever of O1 or O2 |
|
// is a pair of not and a namespace name must be the value. |
|
// +5.1 If the negated value is a namespace name, then The appropriate case |
|
// among the following must be true: |
|
// +5.1.1 If the set includes both the namespace name and absent, then any |
|
// must be the value. |
|
// +5.1.2 If the set includes the namespace name but does not include |
|
// absent, then a pair of not and absent must be the value. |
|
// +5.1.3 If the set does not include the namespace name but includes |
|
// absent, then the union is not expressible. |
|
// +5.1.4 If the set does not include either the namespace name or absent, |
|
// then whichever of O1 or O2 is a pair of not and a namespace name must be |
|
// the value. |
|
// +5.2 If the negated value is absent, then The appropriate case among the |
|
// following must be true: |
|
// +5.2.1 If the set includes absent, then any must be the value. |
|
// +5.2.2 If the set does not include absent, then whichever of O1 or O2 is |
|
// a pair of not and a namespace name must be the value. |
|
|
|
else if ( ((fType == NSCONSTRAINT_NOT) && (wildcard.fType == NSCONSTRAINT_LIST)) || |
|
((fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_NOT)) ) { |
|
String[] other = null; |
|
String[] list = null; |
|
|
|
if (fType == NSCONSTRAINT_NOT) { |
|
other = fNamespaceList; |
|
list = wildcard.fNamespaceList; |
|
} |
|
else { |
|
other = wildcard.fNamespaceList; |
|
list = fNamespaceList; |
|
} |
|
|
|
boolean foundAbsent = elementInSet(ABSENT, list); |
|
|
|
if (other[0] != ABSENT) { |
|
boolean foundNS = elementInSet(other[0], list); |
|
if (foundNS && foundAbsent) { |
|
unionWildcard.fType = NSCONSTRAINT_ANY; |
|
} else if (foundNS && !foundAbsent) { |
|
unionWildcard.fType = NSCONSTRAINT_NOT; |
|
unionWildcard.fNamespaceList = new String[2]; |
|
unionWildcard.fNamespaceList[0] = ABSENT; |
|
unionWildcard.fNamespaceList[1] = ABSENT; |
|
} else if (!foundNS && foundAbsent) { |
|
return null; |
|
} else { |
|
unionWildcard.fType = NSCONSTRAINT_NOT; |
|
unionWildcard.fNamespaceList = other; |
|
} |
|
} else { |
|
if (foundAbsent) { |
|
unionWildcard.fType = NSCONSTRAINT_ANY; |
|
} else { |
|
unionWildcard.fType = NSCONSTRAINT_NOT; |
|
unionWildcard.fNamespaceList = other; |
|
} |
|
} |
|
} |
|
|
|
return unionWildcard; |
|
|
|
} // performUnionWith |
|
|
|
|
|
|
|
*/ |
|
public XSWildcardDecl performIntersectionWith(XSWildcardDecl wildcard, |
|
short processContents) { |
|
|
|
if (wildcard == null) |
|
return null; |
|
|
|
// For a wildcard's {namespace constraint} value to be the intensional intersection of |
|
// two other such values (call them O1 and O2): the appropriate case among the following |
|
// must be true: |
|
|
|
XSWildcardDecl intersectWildcard = new XSWildcardDecl(); |
|
intersectWildcard.fProcessContents = processContents; |
|
|
|
|
|
if (areSame(wildcard)) { |
|
intersectWildcard.fType = fType; |
|
intersectWildcard.fNamespaceList = fNamespaceList; |
|
} |
|
|
|
|
|
else if ( (fType == NSCONSTRAINT_ANY) || (wildcard.fType == NSCONSTRAINT_ANY) ) { |
|
|
|
XSWildcardDecl other = this; |
|
|
|
if (fType == NSCONSTRAINT_ANY) |
|
other = wildcard; |
|
|
|
intersectWildcard.fType = other.fType; |
|
intersectWildcard.fNamespaceList = other.fNamespaceList; |
|
} |
|
|
|
// -3 If either O1 or O2 is a pair of not and a namespace name and the other is a set of |
|
// (namespace names or absent), then that set, minus the negated namespace name if |
|
// it was in the set, must be the value. |
|
// +3 If either O1 or O2 is a pair of not and a namespace name and the other |
|
// is a set of (namespace names or absent), then that set, minus the negated |
|
// namespace name if it was in the set, then minus absent if it was in the |
|
// set, must be the value. |
|
|
|
else if ( ((fType == NSCONSTRAINT_NOT) && (wildcard.fType == NSCONSTRAINT_LIST)) || |
|
((fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_NOT)) ) { |
|
String[] list = null; |
|
String[] other = null; |
|
|
|
if (fType == NSCONSTRAINT_NOT) { |
|
other = fNamespaceList; |
|
list = wildcard.fNamespaceList; |
|
} |
|
else { |
|
other = wildcard.fNamespaceList; |
|
list = fNamespaceList; |
|
} |
|
|
|
int listSize = list.length; |
|
String[] intersect = new String[listSize]; |
|
int newSize = 0; |
|
for (int i = 0; i < listSize; i++) { |
|
if (list[i] != other[0] && list[i] != ABSENT) |
|
intersect[newSize++] = list[i]; |
|
} |
|
|
|
intersectWildcard.fType = NSCONSTRAINT_LIST; |
|
intersectWildcard.fNamespaceList = new String[newSize]; |
|
System.arraycopy(intersect, 0, intersectWildcard.fNamespaceList, 0, newSize); |
|
} |
|
|
|
// 4 If both O1 and O2 are sets of (namespace names or absent), then the intersection of those |
|
|
|
else if ( (fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_LIST) ) { |
|
intersectWildcard.fType = NSCONSTRAINT_LIST; |
|
intersectWildcard.fNamespaceList = intersect2sets(fNamespaceList, wildcard.fNamespaceList); |
|
} |
|
|
|
// -5 If the two are negations of different namespace names, then the intersection is not expressible. |
|
// +5 If the two are negations of namespace names or absent, then The |
|
// appropriate case among the following must be true: |
|
// +5.1 If the two are negations of different namespace names, then the |
|
// intersection is not expressible. |
|
// +5.2 If one of the two is a pair of not and absent, the other must be |
|
// the value. |
|
|
|
else if (fType == NSCONSTRAINT_NOT && wildcard.fType == NSCONSTRAINT_NOT) { |
|
if (fNamespaceList[0] != ABSENT && wildcard.fNamespaceList[0] != ABSENT) |
|
return null; |
|
|
|
XSWildcardDecl other = this; |
|
if (fNamespaceList[0] == ABSENT) |
|
other = wildcard; |
|
|
|
intersectWildcard.fType = other.fType; |
|
intersectWildcard.fNamespaceList = other.fNamespaceList; |
|
} |
|
|
|
return intersectWildcard; |
|
|
|
} // performIntersectionWith |
|
|
|
private boolean areSame(XSWildcardDecl wildcard) { |
|
if (fType == wildcard.fType) { |
|
|
|
if (fType == NSCONSTRAINT_ANY) |
|
return true; |
|
|
|
// ##other, only check the negated value |
|
// * when we support not(list), we need to check in the same way |
|
|
|
if (fType == NSCONSTRAINT_NOT) |
|
return fNamespaceList[0] == wildcard.fNamespaceList[0]; |
|
|
|
// ## list, must have the same length, |
|
// and each item in one list must appear in the other one |
|
|
|
if (fNamespaceList.length == wildcard.fNamespaceList.length) { |
|
for (int i=0; i<fNamespaceList.length; i++) { |
|
if (!elementInSet(fNamespaceList[i], wildcard.fNamespaceList)) |
|
return false; |
|
} |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} // areSame |
|
|
|
String[] intersect2sets(String[] one, String[] theOther){ |
|
String[] result = new String[Math.min(one.length,theOther.length)]; |
|
|
|
|
|
int count = 0; |
|
for (int i=0; i<one.length; i++) { |
|
if (elementInSet(one[i], theOther)) |
|
result[count++] = one[i]; |
|
} |
|
|
|
String[] result2 = new String[count]; |
|
System.arraycopy(result, 0, result2, 0, count); |
|
|
|
return result2; |
|
} |
|
|
|
String[] union2sets(String[] one, String[] theOther){ |
|
String[] result1 = new String[one.length]; |
|
|
|
|
|
int count = 0; |
|
for (int i=0; i<one.length; i++) { |
|
if (!elementInSet(one[i], theOther)) |
|
result1[count++] = one[i]; |
|
} |
|
|
|
String[] result2 = new String[count+theOther.length]; |
|
System.arraycopy(result1, 0, result2, 0, count); |
|
System.arraycopy(theOther, 0, result2, count, theOther.length); |
|
|
|
return result2; |
|
} |
|
|
|
boolean subset2sets(String[] subSet, String[] superSet){ |
|
for (int i=0; i<subSet.length; i++) { |
|
if (!elementInSet(subSet[i], superSet)) |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
boolean elementInSet(String ele, String[] set){ |
|
boolean found = false; |
|
for (int i=0; i<set.length && !found; i++) { |
|
if (ele==set[i]) |
|
found = true; |
|
} |
|
|
|
return found; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private String fDescription = null; |
|
public String toString() { |
|
if (fDescription == null) { |
|
StringBuffer buffer = new StringBuffer(); |
|
buffer.append("WC["); |
|
switch (fType) { |
|
case NSCONSTRAINT_ANY: |
|
buffer.append(SchemaSymbols.ATTVAL_TWOPOUNDANY); |
|
break; |
|
case NSCONSTRAINT_NOT: |
|
buffer.append(SchemaSymbols.ATTVAL_TWOPOUNDOTHER); |
|
buffer.append(":\""); |
|
if (fNamespaceList[0] != null) |
|
buffer.append(fNamespaceList[0]); |
|
buffer.append("\""); |
|
break; |
|
case NSCONSTRAINT_LIST: |
|
if (fNamespaceList.length == 0) |
|
break; |
|
buffer.append("\""); |
|
if (fNamespaceList[0] != null) |
|
buffer.append(fNamespaceList[0]); |
|
buffer.append("\""); |
|
for (int i = 1; i < fNamespaceList.length; i++) { |
|
buffer.append(",\""); |
|
if (fNamespaceList[i] != null) |
|
buffer.append(fNamespaceList[i]); |
|
buffer.append("\""); |
|
} |
|
break; |
|
} |
|
buffer.append(']'); |
|
fDescription = buffer.toString(); |
|
} |
|
|
|
return fDescription; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public short getType() { |
|
return XSConstants.WILDCARD; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public String getName() { |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public String getNamespace() { |
|
return null; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public short getConstraintType() { |
|
return fType; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public StringList getNsConstraintList() { |
|
return new StringListImpl(fNamespaceList, fNamespaceList == null ? 0 : fNamespaceList.length); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public short getProcessContents() { |
|
return fProcessContents; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public String getProcessContentsAsString() { |
|
switch (fProcessContents) { |
|
case XSWildcardDecl.PC_SKIP: return "skip"; |
|
case XSWildcardDecl.PC_LAX: return "lax"; |
|
case XSWildcardDecl.PC_STRICT: return "strict"; |
|
default: return "invalid value"; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public XSAnnotation getAnnotation() { |
|
return (fAnnotations != null) ? (XSAnnotation) fAnnotations.item(0) : null; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public XSObjectList getAnnotations() { |
|
return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public XSNamespaceItem getNamespaceItem() { |
|
return null; |
|
} |
|
|
|
} // class XSWildcardDecl |