neilg 2002/08/16 12:58:06
Modified: java/src/org/apache/xerces/impl/xs XMLSchemaValidator.java
java/src/org/apache/xerces/impl/xs/identity Field.java
FieldActivator.java Selector.java XPathMatcher.java
Log:
"fix" for bug 11571. The bug report was wrong, but this fixes an NPE that it
provoked.
Also, identity constraints now properly handle cases where an identity constraint is
defined on a recursive element. I have also reworked some code to save
some method calls.
Revision Changes Path
1.83 +97 -60
xml-xerces/java/src/org/apache/xerces/impl/xs/XMLSchemaValidator.java
Index: XMLSchemaValidator.java
===================================================================
RCS file:
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/xs/XMLSchemaValidator.java,v
retrieving revision 1.82
retrieving revision 1.83
diff -u -r1.82 -r1.83
--- XMLSchemaValidator.java 16 Aug 2002 18:08:37 -0000 1.82
+++ XMLSchemaValidator.java 16 Aug 2002 19:58:05 -0000 1.83
@@ -236,6 +236,11 @@
JAXP_SCHEMA_SOURCE
};
+ // this is the number of valuestores of each kind
+ // we expect an element to have. It's almost
+ // never > 1; so leave it at that.
+ protected static final int ID_CONSTRAINT_NUM = 1;
+
//
// Data
//
@@ -1368,14 +1373,12 @@
*
* @param identityConstraint The identity constraint.
*/
- public void startValueScopeFor(IdentityConstraint identityConstraint)
+ public void startValueScopeFor(IdentityConstraint identityConstraint,
+ int initialDepth)
throws XNIException {
- for (int i=0; i<identityConstraint.getFieldCount(); i++) {
- Field field = identityConstraint.getFieldAt(i);
- ValueStoreBase valueStore = fValueStoreCache.getValueStoreFor(field);
- valueStore.startValueScope();
- }
+ ValueStoreBase valueStore =
fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth);
+ valueStore.startValueScope();
} // startValueScopeFor(IdentityConstraint identityConstraint)
@@ -1385,8 +1388,8 @@
*
* @param field The field to activate.
*/
- public XPathMatcher activateField(Field field) throws XNIException {
- ValueStore valueStore = fValueStoreCache.getValueStoreFor(field);
+ public XPathMatcher activateField(Field field, int initialDepth) {
+ ValueStore valueStore =
fValueStoreCache.getValueStoreFor(field.getIdentityConstraint(), initialDepth);
field.setMayMatch(true);
XPathMatcher matcher = field.createMatcher(valueStore);
fMatcherStack.addMatcher(matcher);
@@ -1399,10 +1402,10 @@
*
* @param identityConstraint The identity constraint.
*/
- public void endValueScopeFor(IdentityConstraint identityConstraint)
+ public void endValueScopeFor(IdentityConstraint identityConstraint, int
initialDepth)
throws XNIException {
- ValueStoreBase valueStore =
fValueStoreCache.getValueStoreFor(identityConstraint);
+ ValueStoreBase valueStore =
fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth);
valueStore.endValueScope();
} // endValueScopeFor(IdentityConstraint)
@@ -1413,7 +1416,7 @@
FieldActivator activator = this;
if (selector == null)
return;
- XPathMatcher matcher = selector.createMatcher(activator);
+ XPathMatcher matcher = selector.createMatcher(activator, fElementDepth);
fMatcherStack.addMatcher(matcher);
matcher.startDocumentFragment(fSymbolTable);
}
@@ -2087,19 +2090,25 @@
// handle everything *but* keyref's.
for (int i = oldCount - 1; i >= newCount; i--) {
XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
- IdentityConstraint id;
- if ((id = matcher.getIDConstraint()) != null && id.getCategory() !=
IdentityConstraint.IC_KEYREF) {
- fValueStoreCache.transplant(id);
+ if(matcher instanceof Selector.Matcher) {
+ Selector.Matcher selMatcher = (Selector.Matcher)matcher;
+ IdentityConstraint id;
+ if ((id = selMatcher.getIdentityConstraint()) != null &&
id.getCategory() != IdentityConstraint.IC_KEYREF) {
+ fValueStoreCache.transplant(id, selMatcher.getInitialDepth());
+ }
}
}
// now handle keyref's/...
for (int i = oldCount - 1; i >= newCount; i--) {
XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
- IdentityConstraint id;
- if ((id = matcher.getIDConstraint()) != null && id.getCategory() ==
IdentityConstraint.IC_KEYREF) {
- ValueStoreBase values = fValueStoreCache.getValueStoreFor(id);
- if (values != null) // nothing to do if nothing matched!
- values.endDocumentFragment();
+ if(matcher instanceof Selector.Matcher) {
+ Selector.Matcher selMatcher = (Selector.Matcher)matcher;
+ IdentityConstraint id;
+ if ((id = selMatcher.getIdentityConstraint()) != null &&
id.getCategory() == IdentityConstraint.IC_KEYREF) {
+ ValueStoreBase values = fValueStoreCache.getValueStoreFor(id,
selMatcher.getInitialDepth());
+ if (values != null) // nothing to do if nothing matched!
+ values.endDocumentFragment();
+ }
}
}
fValueStoreCache.endElement();
@@ -3098,11 +3107,11 @@
// destroys this ValueStore; useful when, for instance, a
// locally-scoped ID constraint is involved.
- public void destroy() {
+ public void clear() {
fValuesCount = 0;
fValues.clear();
fValueTuples.removeAllElements();
- } // end destroy():void
+ } // end clear():void
// appends the contents of one ValueStore to those of us.
public void append(ValueStoreBase newVal) {
@@ -3498,7 +3507,15 @@
/** stores all global Values stores. */
protected final Vector fValueStores = new Vector();
- /** Values stores associated to specific identity constraints. */
+ /**
+ * Values stores associated to specific identity constraints.
+ * This hashtable maps IdentityConstraints and
+ * the 0-based element on which their selectors first matched to
+ * a corresponding ValueStore. This should take care
+ * of all cases, including where ID constraints with
+ * descendant-or-self axes occur on recursively-defined
+ * elements.
+ */
protected final Hashtable fIdentityConstraint2ValueStoreMap = new
Hashtable();
// sketch of algorithm:
@@ -3574,8 +3591,7 @@
* Initializes the value stores for the specified element
* declaration.
*/
- public void initValueStoresFor(XSElementDecl eDecl)
- throws XNIException {
+ public void initValueStoresFor(XSElementDecl eDecl) {
// initialize value stores for unique fields
IdentityConstraint [] icArray = eDecl.fIDConstraints;
int icCount = eDecl.fIDCPos;
@@ -3584,56 +3600,52 @@
case (IdentityConstraint.IC_UNIQUE):
// initialize value stores for unique fields
UniqueOrKey unique = (UniqueOrKey)icArray[i];
- UniqueValueStore uniqueValueStore =
(UniqueValueStore)fIdentityConstraint2ValueStoreMap.get(unique);
- if (uniqueValueStore != null) {
- // NOTE: If already initialized, don't need to
- // do it again. -Ac
- continue;
+ LocalIDKey toHash = new LocalIDKey (unique, fElementDepth);
+ UniqueValueStore uniqueValueStore =
(UniqueValueStore)fIdentityConstraint2ValueStoreMap.get(toHash);
+ if (uniqueValueStore == null) {
+ uniqueValueStore = new UniqueValueStore(unique);
+ fIdentityConstraint2ValueStoreMap.put(toHash,
uniqueValueStore);
+ } else {
+ uniqueValueStore.clear();
}
- uniqueValueStore = new UniqueValueStore(unique);
fValueStores.addElement(uniqueValueStore);
- fIdentityConstraint2ValueStoreMap.put(unique, uniqueValueStore);
break;
case (IdentityConstraint.IC_KEY):
// initialize value stores for key fields
UniqueOrKey key = (UniqueOrKey)icArray[i];
- KeyValueStore keyValueStore =
(KeyValueStore)fIdentityConstraint2ValueStoreMap.get(key);
- if (keyValueStore != null) {
- // NOTE: If already initialized, don't need to
- // do it again. -Ac
- continue;
+ toHash = new LocalIDKey(key, fElementDepth);
+ KeyValueStore keyValueStore =
(KeyValueStore)fIdentityConstraint2ValueStoreMap.get(toHash);
+ if (keyValueStore == null) {
+ keyValueStore = new KeyValueStore(key);
+ fIdentityConstraint2ValueStoreMap.put(toHash,
keyValueStore);
+ } else {
+ keyValueStore.clear();
}
- keyValueStore = new KeyValueStore(key);
fValueStores.addElement(keyValueStore);
- fIdentityConstraint2ValueStoreMap.put(key, keyValueStore);
break;
case (IdentityConstraint.IC_KEYREF):
- // initialize value stores for key reference fields
+ // initialize value stores for keyRef fields
KeyRef keyRef = (KeyRef)icArray[i];
- KeyRefValueStore keyRefValueStore =
(KeyRefValueStore)fIdentityConstraint2ValueStoreMap.get(keyRef);
- if (keyRefValueStore != null) {
- // NOTE: If already initialized, don't need to
- // do it again. -Ac
- continue;
+ toHash = new LocalIDKey(keyRef, fElementDepth);
+ KeyRefValueStore keyRefValueStore =
(KeyRefValueStore)fIdentityConstraint2ValueStoreMap.get(toHash);
+ if (keyRefValueStore == null) {
+ keyRefValueStore = new KeyRefValueStore(keyRef, null);
+ fIdentityConstraint2ValueStoreMap.put(toHash,
keyRefValueStore);
+ } else {
+ keyRefValueStore.clear();
}
- keyRefValueStore = new KeyRefValueStore(keyRef, null);
fValueStores.addElement(keyRefValueStore);
- fIdentityConstraint2ValueStoreMap.put(keyRef, keyRefValueStore);
break;
}
}
} // initValueStoresFor(XSElementDecl)
- /** Returns the value store associated to the specified field. */
- public ValueStoreBase getValueStoreFor(Field field) {
- IdentityConstraint identityConstraint = field.getIdentityConstraint();
-
return(ValueStoreBase)fIdentityConstraint2ValueStoreMap.get(identityConstraint);
- } // getValueStoreFor(Field):ValueStoreBase
-
/** Returns the value store associated to the specified IdentityConstraint.
*/
- public ValueStoreBase getValueStoreFor(IdentityConstraint id) {
- return(ValueStoreBase)fIdentityConstraint2ValueStoreMap.get(id);
- } // getValueStoreFor(IdentityConstraint):ValueStoreBase
+ public ValueStoreBase getValueStoreFor(IdentityConstraint id, int
initialDepth) {
+ ValueStoreBase vb =
(ValueStoreBase)fIdentityConstraint2ValueStoreMap.get(new LocalIDKey(id,
initialDepth));
+ // vb should *never* be null!
+ return vb;
+ } // getValueStoreFor(IdentityConstraint, int):ValueStoreBase
/** Returns the global value store associated to the specified
IdentityConstraint. */
public ValueStoreBase getGlobalValueStoreFor(IdentityConstraint id) {
@@ -3643,10 +3655,9 @@
// associated with id and moves them into the global
// hashtable, if id is a <unique> or a <key>.
// If it's a <keyRef>, then we leave it for later.
- public void transplant(IdentityConstraint id) {
+ public void transplant(IdentityConstraint id, int initialDepth) {
+ ValueStoreBase newVals =
(ValueStoreBase)fIdentityConstraint2ValueStoreMap.get(new LocalIDKey(id,
initialDepth));
if (id.getCategory() == IdentityConstraint.IC_KEYREF) return;
- ValueStoreBase newVals =
(ValueStoreBase)fIdentityConstraint2ValueStoreMap.get(id);
- fIdentityConstraint2ValueStoreMap.remove(id);
ValueStoreBase currVals =
(ValueStoreBase)fGlobalIDConstraintMap.get(id);
if (currVals != null) {
currVals.append(newVals);
@@ -3658,7 +3669,7 @@
} // transplant(id)
/** Check identity constraints. */
- public void endDocument() throws XNIException {
+ public void endDocument() {
int count = fValueStores.size();
for (int i = 0; i < count; i++) {
@@ -3875,4 +3886,30 @@
} // class Entry
} // class OrderedHashtable
+
+ // the purpose of this class is to enable IdentityConstraint,int
+ // pairs to be used easily as keys in Hashtables.
+ protected class LocalIDKey {
+ private IdentityConstraint fId;
+ private int fDepth;
+
+ public LocalIDKey (IdentityConstraint id, int depth) {
+ fId = id;
+ fDepth = depth;
+ } // init(IdentityConstraint, int)
+
+ // object method
+ public int hashCode() {
+ return fId.hashCode()+fDepth;
+ }
+
+ public boolean equals(Object localIDKey) {
+ if(localIDKey instanceof LocalIDKey) {
+ LocalIDKey lIDKey = (LocalIDKey)localIDKey;
+ return (lIDKey.fId == fId && lIDKey.fDepth == fDepth);
+ }
+ return false;
+ }
+ } // class LocalIDKey
+
} // class SchemaValidator
1.5 +2 -2
xml-xerces/java/src/org/apache/xerces/impl/xs/identity/Field.java
Index: Field.java
===================================================================
RCS file:
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/xs/identity/Field.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- Field.java 13 Aug 2002 22:32:44 -0000 1.4
+++ Field.java 16 Aug 2002 19:58:06 -0000 1.5
@@ -197,7 +197,7 @@
/** Constructs a field matcher. */
public Matcher(Field.XPath xpath, ValueStore store) {
- super(xpath, null);
+ super(xpath);
fStore = store;
} // <init>(Field.XPath,ValueStore)
1.3 +8 -4
xml-xerces/java/src/org/apache/xerces/impl/xs/identity/FieldActivator.java
Index: FieldActivator.java
===================================================================
RCS file:
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/xs/identity/FieldActivator.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- FieldActivator.java 29 Jan 2002 01:15:15 -0000 1.2
+++ FieldActivator.java 16 Aug 2002 19:58:06 -0000 1.3
@@ -80,8 +80,10 @@
* the value store.
*
* @param identityConstraint The identity constraint.
+ * @param initialDepth the depth at which the selector began matching
*/
- public void startValueScopeFor(IdentityConstraint identityConstraint);
+ public void startValueScopeFor(IdentityConstraint identityConstraint,
+ int initialDepth);
/**
* Request to activate the specified field. This method returns the
@@ -90,14 +92,16 @@
* it is permitted to match a value--that is, to call the field's
setMayMatch(boolean) method.
*
* @param field The field to activate.
+ * @param initialDepth the 0-indexed depth in the instance document at which
the Selector began to match.
*/
- public XPathMatcher activateField(Field field);
+ public XPathMatcher activateField(Field field, int initialDepth);
/**
* Ends the value scope for the specified identity constraint.
*
* @param identityConstraint The identity constraint.
+ * @param initialDepth the 0-indexed depth where the Selector began to match.
*/
- public void endValueScopeFor(IdentityConstraint identityConstraint);
+ public void endValueScopeFor(IdentityConstraint identityConstraint, int
initialDepth);
} // interface FieldActivator
1.8 +36 -13
xml-xerces/java/src/org/apache/xerces/impl/xs/identity/Selector.java
Index: Selector.java
===================================================================
RCS file:
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/xs/identity/Selector.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- Selector.java 14 Aug 2002 16:02:22 -0000 1.7
+++ Selector.java 16 Aug 2002 19:58:06 -0000 1.8
@@ -88,6 +88,10 @@
/** Identity constraint. */
protected IdentityConstraint fIdentityConstraint;
+ // the Identity constraint we're the matcher for. Only
+ // used for selectors!
+ protected IdentityConstraint fIDConstraint;
+
//
// Constructors
//
@@ -109,15 +113,19 @@
} // getXPath():org.apache.xerces.v1.schema.identity.XPath
/** Returns the identity constraint. */
- public IdentityConstraint getIdentityConstraint() {
+ public IdentityConstraint getIDConstraint() {
return fIdentityConstraint;
- } // getIdentityConstraint():IdentityConstraint
+ } // getIDConstraint():IdentityConstraint
// factory method
- /** Creates a selector matcher. */
- public XPathMatcher createMatcher(FieldActivator activator) {
- return new Selector.Matcher(fXPath, activator);
+ /** Creates a selector matcher.
+ * @param activator The activator for this selector's fields.
+ * @param initialDepth The depth in the document at which this matcher began
its life;
+ * used in correctly handling recursive elements.
+ */
+ public XPathMatcher createMatcher(FieldActivator activator, int initialDepth) {
+ return new Selector.Matcher(fXPath, activator, initialDepth);
} // createMatcher(FieldActivator):XPathMatcher
//
@@ -176,7 +184,7 @@
*
* @author Andy Clark, IBM
*/
- protected class Matcher
+ public class Matcher
extends XPathMatcher {
//
@@ -186,6 +194,9 @@
/** Field activator. */
protected FieldActivator fFieldActivator;
+ /** Initial depth in the document at which this matcher was created. */
+ protected int fInitialDepth;
+
/** Element depth. */
protected int fElementDepth;
@@ -197,9 +208,11 @@
//
/** Constructs a selector matcher. */
- public Matcher(Selector.XPath xpath, FieldActivator activator) {
- super(xpath, Selector.this.fIdentityConstraint);
+ public Matcher(Selector.XPath xpath, FieldActivator activator,
+ int initialDepth) {
+ super(xpath);
fFieldActivator = activator;
+ fInitialDepth = initialDepth;
} // <init>(Selector.XPath,FieldActivator)
//
@@ -234,11 +247,11 @@
if ((fMatchedDepth == -1 && ((matched & MATCHED) == MATCHED)) ||
((matched & MATCHED_DESCENDANT) == MATCHED_DESCENDANT)) {
fMatchedDepth = fElementDepth;
- fFieldActivator.startValueScopeFor(fIdentityConstraint);
+ fFieldActivator.startValueScopeFor(fIdentityConstraint,
fInitialDepth);
int count = fIdentityConstraint.getFieldCount();
for (int i = 0; i < count; i++) {
Field field = fIdentityConstraint.getFieldAt(i);
- XPathMatcher matcher = fFieldActivator.activateField(field);
+ XPathMatcher matcher = fFieldActivator.activateField(field,
fInitialDepth);
matcher.startElement(element, attributes, elementDecl);
}
}
@@ -249,9 +262,19 @@
super.endElement(element, eDecl, ePSVI);
if (fElementDepth-- == fMatchedDepth) {
fMatchedDepth = -1;
- fFieldActivator.endValueScopeFor(fIdentityConstraint);
+ fFieldActivator.endValueScopeFor(fIdentityConstraint,
fInitialDepth);
}
}
+
+ /** Returns the identity constraint. */
+ public IdentityConstraint getIdentityConstraint() {
+ return fIdentityConstraint;
+ } // getIdentityConstraint():IdentityConstraint
+
+ /** get the initial depth at which this selector matched. */
+ public int getInitialDepth() {
+ return fInitialDepth;
+ } // getInitialDepth(): int
//
// Protected methods
1.10 +2 -32
xml-xerces/java/src/org/apache/xerces/impl/xs/identity/XPathMatcher.java
Index: XPathMatcher.java
===================================================================
RCS file:
/home/cvs/xml-xerces/java/src/org/apache/xerces/impl/xs/identity/XPathMatcher.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- XPathMatcher.java 14 Aug 2002 16:02:22 -0000 1.9
+++ XPathMatcher.java 16 Aug 2002 19:58:06 -0000 1.10
@@ -147,10 +147,6 @@
*/
private int [] fNoMatchDepth;
- // the Identity constraint we're the matcher for. Only
- // used for selectors!
- protected IdentityConstraint fIDConstraint;
-
// the symbolTable for the XPath parser
protected SymbolTable fSymbolTable;
@@ -165,22 +161,7 @@
* @param xpath The xpath.
*/
public XPathMatcher(XPath xpath) {
- this(xpath, null);
- } // <init>(XPath)
-
- /**
- * Constructs an XPath matcher that implements a document fragment
- * handler.
- *
- * @param xpath The xpath.
- * @param shouldBufferContent True if the matcher should buffer the
- * matched content.
- * @param idConstraint: the identity constraint we're matching for;
- * null unless it's a Selector.
- */
- public XPathMatcher(XPath xpath, IdentityConstraint idConstraint) {
fLocationPaths = xpath.getLocationPaths();
- fIDConstraint = idConstraint;
fStepIndexes = new IntStack[fLocationPaths.length];
for(int i=0; i<fStepIndexes.length; i++) fStepIndexes[i] = new IntStack();
fCurrentStep = new int[fLocationPaths.length];
@@ -189,7 +170,7 @@
if (DEBUG_METHODS) {
System.out.println(toString()+"#<init>()");
}
- } // <init>(XPath,boolean)
+ } // <init>(XPath)
//
// Public methods
@@ -206,16 +187,6 @@
return 0;
} // isMatched():int
- // returns whether this XPathMatcher was matching a Selector
- public boolean getIsSelector() {
- return (fIDConstraint == null);
- } // end getIsSelector():boolean
-
- // returns the ID constraint
- public IdentityConstraint getIDConstraint() {
- return fIDConstraint;
- } // end getIDConstraint():IdentityConstraint
-
/** Returns the matched string. */
public String getMatchedString() {
return fMatchedString;
@@ -494,7 +465,6 @@
if (DEBUG_METHODS2) {
System.out.println(toString()+"#endElement("+
"element={"+element+"},"+
- "ID constraint="+fIDConstraint+
")");
}
for(int i = 0; i<fLocationPaths.length; i++) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]