rdonkin 2003/03/12 14:10:52
Modified: digester/src/java/org/apache/commons/digester
ExtendedBaseRules.java
digester/src/test/org/apache/commons/digester
EBRTestCase.java
Log:
Fix for bug #16350. This adds another kind of wildcard match - and ancester tail
match. This allows matching patterns such as a/b/*. Based on a patch submitted by
Kelvin Tan
Revision Changes Path
1.5 +63 -12
jakarta-commons/digester/src/java/org/apache/commons/digester/ExtendedBaseRules.java
Index: ExtendedBaseRules.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/digester/src/java/org/apache/commons/digester/ExtendedBaseRules.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- ExtendedBaseRules.java 2 Feb 2003 16:09:53 -0000 1.4
+++ ExtendedBaseRules.java 12 Mar 2003 22:10:50 -0000 1.5
@@ -102,7 +102,7 @@
* to call.
* <ul>
* <li><code>"a/b/c/?"</code> matches any child whose parent matches
- * <code>"a/b/c"</code>. Exact parent rules take precendence over
+ * <code>"a/b/c"</code>. Exact parent rules take precedence over
* standard wildcard tail endings.</li>
* <li><code>"*/a/b/c/?"</code> matches any child whose parent matches
* "*/a/b/c"</code>. The longest matching still applies to parent
@@ -110,7 +110,18 @@
* that standard wildcard matches with the same level of depth are
* chosen in preference.</li>
* </ul></li>
- * <li><em>Universal Wildcard Match </em> - Any pattern prefixed with '!'
+ * <li><em>Ancester Match</em> - Will match elements who parentage includes
+ * a particular sequence of elements.
+ * <ul>
+ * <li><code>"a/b/*"</code> matches any element whose parentage path starts
with
+ * 'a' then 'b'. Exact parent and parent match rules take precedence. The
longest
+ * ancester match will take precedence.</li>
+ * <li><code>"*/a/b/*"</code> matches any elements whose parentage path
contains
+ * an element 'a' followed by an element 'b'. The longest matching still
applies
+ * but the length excludes the '*' at the end.</li>
+ * </ul>
+ * </li>
+ * <li><em>Universal Wildcard Match</em> - Any pattern prefixed with '!'
* bypasses the longest matching rule. Even if there is an exact match
* or a longer wildcard match, patterns prefixed by '!' will still be
* tested to see if they match. This can be used for example to specify
@@ -122,6 +133,10 @@
* matching <code>"a/b"</code>.</li>
* <li>Pattern <code>"!*/a/b/?"</code> matches any child of a parent
* matching <code>"!*/a/b"</code></li>
+ * <li>Pattern <code>"!a/b/*"</code> matches any element whose parentage path
starts with
+ * "a" then "b".</li>
+ * <li>Pattern <code>"!*/a/b/*"</code> matches any elements whose parentage
path contains
+ * 'a/b'</li>
* </ul></li>
* <li><em>Wild Match</em>
* <ul>
@@ -207,7 +222,6 @@
* @param pattern Nesting pattern to be matched
*/
public List match(String namespace, String pattern) {
-
// calculate the pattern of the parent
// (if the element has one)
String parentPattern = "";
@@ -266,6 +280,16 @@
// we have a match!
// so ignore all basic matches from now on
ignoreBasicMatches = true;
+
+ } else {
+ // we don't have a match yet - so try exact ancester
+ //
+ rulesList = findExactAncesterMatch(parentPattern);
+ if (rulesList != null) {
+ // we have a match!
+ // so ignore all basic matches from now on
+ ignoreBasicMatches = true;
+ }
}
}
}
@@ -289,22 +313,32 @@
key = key.substring(1, key.length());
}
-
+
// don't need to check exact matches
- if (key.startsWith("*/")) {
+ if (key.startsWith("*/") || (isUniversal && key.endsWith("/*"))) {
boolean parentMatched = false;
boolean basicMatched = false;
+ boolean ancesterMatched = false;
if (key.endsWith("/?")) {
// try for a parent match
parentMatched = parentMatch(key, pattern, parentPattern);
+ } else if (key.endsWith("/*")) {
+ // check for ancester match
+ int patternStart = 0;
+ if (key.startsWith("*/")) {
+ patternStart = 2;
+ }
+ ancesterMatched =
+ (pattern.lastIndexOf(key.substring(patternStart,
key.length() - 2)) > -1);
+
} else {
// try for a base match
basicMatched = basicMatch(key, pattern);
}
- if (parentMatched || basicMatched) {
+ if (parentMatched || basicMatched || ancesterMatched) {
if (isUniversal) {
// universal rules go straight in
// (no longest matching rule)
@@ -318,7 +352,7 @@
// ensure that all parent matches are SHORTER
// than rules with same level of matching
int keyLength = key.length();
- if (parentMatched) {
+ if (parentMatched || ancesterMatched) {
keyLength--;
}
@@ -408,5 +442,22 @@
return (pattern.equals(key.substring(2)) ||
pattern.endsWith(key.substring(1)));
}
-
+
+ /**
+ * Finds an exact ancester match for given pattern
+ */
+ private List findExactAncesterMatch(String parentPattern) {
+ List matchingRules = null;
+ int lastIndex = parentPattern.length();
+ while (lastIndex-- > 0) {
+ lastIndex = parentPattern.lastIndexOf('/', lastIndex);
+ if (lastIndex > 0) {
+ matchingRules = (List) this.cache.get(parentPattern.substring(0,
lastIndex) + "/*");
+ if (matchingRules != null) {
+ return matchingRules;
+ }
+ }
+ }
+ return null;
+ }
}
1.7 +67 -4
jakarta-commons/digester/src/test/org/apache/commons/digester/EBRTestCase.java
Index: EBRTestCase.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/digester/src/test/org/apache/commons/digester/EBRTestCase.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- EBRTestCase.java 2 Feb 2003 15:52:14 -0000 1.6
+++ EBRTestCase.java 12 Mar 2003 22:10:51 -0000 1.7
@@ -384,4 +384,67 @@
digester.getRules().clear();
}
+
+ public void testAncesterMatch() throws Exception {
+ System.out.println("Starting ancester match...");
+ // test fixed root ancester
+ digester.getRules().clear();
+
+ digester.addRule("!a/b/*", new TestRule("uni-a-b-star"));
+ digester.addRule("a/b/*", new TestRule("a-b-star"));
+ digester.addRule("a/b/c", new TestRule("a-b-c"));
+ digester.addRule("a/b/?", new TestRule("a-b-child"));
+
+ List
+ list = digester.getRules().match(null, "a/b/c");
+
+ assertEquals("Simple ancester matches (1)", 2, list.size());
+ assertEquals("Univeral ancester mismatch (1)", "uni-a-b-star" , ((TestRule)
list.get(0)).getIdentifier());
+ assertEquals("Parent precedence failure", "a-b-c" , ((TestRule)
list.get(1)).getIdentifier());
+
+ list = digester.getRules().match(null, "a/b/b");
+ assertEquals("Simple ancester matches (2)", 2, list.size());
+ assertEquals("Univeral ancester mismatch (2)", "uni-a-b-star" , ((TestRule)
list.get(0)).getIdentifier());
+ assertEquals("Child precedence failure", "a-b-child" , ((TestRule)
list.get(1)).getIdentifier());
+
+ list = digester.getRules().match(null, "a/b/d");
+ assertEquals("Simple ancester matches (3)", 2, list.size());
+ assertEquals("Univeral ancester mismatch (3)", "uni-a-b-star" , ((TestRule)
list.get(0)).getIdentifier());
+ assertEquals("Ancester mismatch (1)", "a-b-child" , ((TestRule)
list.get(1)).getIdentifier());
+
+ list = digester.getRules().match(null, "a/b/d/e/f");
+ assertEquals("Simple ancester matches (4)", 2, list.size());
+ assertEquals("Univeral ancester mismatch (4)", "uni-a-b-star" , ((TestRule)
list.get(0)).getIdentifier());
+ assertEquals("Ancester mismatch (2)", "a-b-star" , ((TestRule)
list.get(1)).getIdentifier());
+
+ // test wild root ancester
+ digester.getRules().clear();
+
+ digester.addRule("!*/a/b/*", new TestRule("uni-star-a-b-star"));
+ digester.addRule("*/b/c/*", new TestRule("star-b-c-star"));
+ digester.addRule("*/b/c/d", new TestRule("star-b-c-d"));
+ digester.addRule("a/b/c", new TestRule("a-b-c"));
+
+ list = digester.getRules().match(null, "a/b/c");
+ assertEquals("Wild ancester match (1)", 2, list.size());
+ assertEquals(
+ "Univeral ancester mismatch (5)",
+ "uni-star-a-b-star" ,
+ ((TestRule) list.get(0)).getIdentifier());
+ assertEquals("Match missed (1)", "a-b-c" , ((TestRule)
list.get(1)).getIdentifier());
+
+ list = digester.getRules().match(null, "b/c");
+ assertEquals("Wild ancester match (2)", 1, list.size());
+ assertEquals("Match missed (2)", "star-b-c-star" , ((TestRule)
list.get(0)).getIdentifier());
+
+ list = digester.getRules().match(null, "a/b/c/d");
+ assertEquals("Wild ancester match (3)", 2, list.size());
+ assertEquals("Match missed (3)", "uni-star-a-b-star" , ((TestRule)
list.get(0)).getIdentifier());
+ assertEquals("Match missed (4)", "star-b-c-d" , ((TestRule)
list.get(1)).getIdentifier());
+
+ list = digester.getRules().match(null, "b/b/c/e/d");
+ assertEquals("Wild ancester match (2)", 1, list.size());
+ assertEquals("Match missed (5)", "star-b-c-star" , ((TestRule)
list.get(0)).getIdentifier());
+ System.out.println("Finished ancester match.");
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]