digester里面的所有add相关的方法都是调用了addRule这个方法,当然这个方法也可以直接调用,该方法就是把一个pattern和一个rule的实现类对象进行绑定,用户可以自己实现一个rule的实现类,也可以用jdk提供的一些rule实现类,例如CallMethodRule,他被addCallMethod()这个方法使用,所以当我们调用addCallMethod(),就等于使用了CallMethodRule。
public void addCallMethod(String pattern, String methodName) {
addRule(
pattern,
new CallMethodRule(methodName));
}
我们实现Rule主要是实现begin body end这几个方法,这几个方法分别会在startElement和endElement方法中被调用,这两个方法分别对应xml元素头(例如 )和元素位(例如 )
public void addRule(String pattern, Rule rule) {
rule.setDigester(this);
getRules().add(pattern, rule);
}
RulesBase的add方法
public void add(String pattern, Rule rule) {
// to help users who accidently add '/' to the end of their patterns
int patternLength = pattern.length();
if (patternLength>1 && pattern.endsWith("/")) {
pattern = pattern.substring(0, patternLength-1);
}
List list = cache.get(pattern);
if (list == null) {
list = new ArrayList();
cache.put(pattern, list);
}
list.add(rule);//将pattern和Rule放到cache(hashmap)中,也就是一个pattern对应一组Rule
rules.add(rule);
if (this.digester != null) {
rule.setDigester(this.digester);
}
if (this.namespaceURI != null) {
rule.setNamespaceURI(this.namespaceURI);
}
}
public void startElement(String namespaceURI, String localName,
String qName, Attributes list)
throws SAXException {
boolean debug = log.isDebugEnabled();
if (saxLog.isDebugEnabled()) {
saxLog.debug("startElement(" + namespaceURI + "," + localName + "," +
qName + ")");
}
// Parse system properties
list = updateAttributes(list);//解析元素的属性,放到list中
// Save the body text accumulated for our surrounding element
bodyTexts.push(bodyText);//把bodyText存起来,例如abc这个abc就是bodyText
bodyText = new StringBuilder();
// the actual element name is either in localName or qName, depending
// on whether the parser is namespace aware
String name = localName;//获取元素名
if ((name == null) || (name.length() < 1)) {
name = qName; //获取元素名
}
// Compute the current matching rule
StringBuilder sb = new StringBuilder(match);
if (match.length() > 0) {
sb.append('/');
}
sb.append(name); //多级元素组成目录格式,类似/a/b/c
match = sb.toString();
if (debug) {
log.debug(" New match='" + match + "'");
}
// Fire "begin" events for all relevant rules
List rules = getRules().match(namespaceURI, match);//利用match与之前记录在cache里的pattern做匹配,得到一组rule
matches.push(rules);//存起来到endelement会用
if ((rules != null) && (rules.size() > 0)) {
for (int i = 0; i < rules.size(); i++) {
try {
Rule rule = rules.get(i);
if (debug) {
log.debug(" Fire begin() for " + rule);
}
rule.begin(namespaceURI, name, list);//依次执行这组rule
} catch (Exception e) {
log.error("Begin event threw exception", e);
throw createSAXException(e);
} catch (Error e) {
log.error("Begin event threw error", e);
throw e;
}
}
} else {
if (debug) {
log.debug(" No rules found matching '" + match + "'.");
}
}
}
public void endElement(String namespaceURI, String localName,
String qName) throws SAXException {
boolean debug = log.isDebugEnabled();
if (debug) {
if (saxLog.isDebugEnabled()) {
saxLog.debug("endElement(" + namespaceURI + "," + localName +
"," + qName + ")");
}
log.debug(" match='" + match + "'");
log.debug(" bodyText='" + bodyText + "'");
}
// Parse system properties
bodyText = updateBodyText(bodyText);//把bodyText中的变量进行替换
// the actual element name is either in localName or qName, depending
// on whether the parser is namespace aware
String name = localName;
if ((name == null) || (name.length() < 1)) {
name = qName;
}
// Fire "body" events for all relevant rules
List rules = matches.pop(); //把之前startelement中的记录弹出,先入后出,等于就是先处理最内层的元素的内容
if ((rules != null) && (rules.size() > 0)) {
String bodyText = this.bodyText.toString();
for (int i = 0; i < rules.size(); i++) {
try {
Rule rule = rules.get(i);
if (debug) {
log.debug(" Fire body() for " + rule);
}
rule.body(namespaceURI, name, bodyText);
} catch (Exception e) {
log.error("Body event threw exception", e);
throw createSAXException(e);
} catch (Error e) {
log.error("Body event threw error", e);
throw e;
}
}
} else {
if (debug) {
log.debug(" No rules found matching '" + match + "'.");
}
if (rulesValidation) {
log.warn(" No rules found matching '" + match + "'.");
}
}
// Recover the body text from the surrounding element
bodyText = bodyTexts.pop();
// Fire "end" events for all relevant rules in reverse order
if (rules != null) {
for (int i = 0; i < rules.size(); i++) {
int j = (rules.size() - i) - 1;
try {
Rule rule = rules.get(j);
if (debug) {
log.debug(" Fire end() for " + rule);
}
rule.end(namespaceURI, name);//依次执行rule,但执行顺序和start时相反
} catch (Exception e) {
log.error("End event threw exception", e);
throw createSAXException(e);
} catch (Error e) {
log.error("End event threw error", e);
throw e;
}
}
}
// Recover the previous match expression
int slash = match.lastIndexOf('/');
if (slash >= 0) {
match = match.substring(0, slash);
} else {
match = "";
}
}
especially,addObjectCreate这个方法
public void addObjectCreate(String pattern, String className,
String attributeName) {
addRule(pattern,
new ObjectCreateRule(className, attributeName));
}
ObjectCreateRule.begin()
public void begin(String namespace, String name, Attributes attributes)
throws Exception {
// Identify the name of the class to instantiate
String realClassName = className;
if (attributeName != null) {
String value = attributes.getValue(attributeName);
if (value != null) {
realClassName = value;
}
}
if (digester.log.isDebugEnabled()) {
digester.log.debug("[ObjectCreateRule]{" + digester.match +
"}New " + realClassName);
}
if (realClassName == null) {
throw new NullPointerException("No class name specified for " +
namespace + " " + name);
}
// Instantiate the new object and push it on the context stack
Class> clazz = digester.getClassLoader().loadClass(realClassName);
Object instance = clazz.newInstance(); //创建类实例
digester.push(instance);//将实例压入栈,目的是后续比如CallMethodRule里的方法会用这个里面的对象,调用这个对象的方法,所以相关的addObjectCreate和addCallMethod要写一起,别隔着其他的addObjectCreate,否则对象会找错
}