public abstract class Rule {
/**
* This method is called when the beginning of a matching XML element
* is encountered. The default implementation delegates to the deprecated
* method {@link #begin(Attributes) begin} without the
* <code>namespace</code> and <code>name</code> parameters, to retain
* backwards compatibility.
*
* @param namespace the namespace URI of the matching element, or an
* empty string if the parser is not namespace aware or the element has
* no namespace
* @param name the local name if the parser is namespace aware, or just
* the element name otherwise
* @param attributes The attribute list of this element
* @since Digester 1.4
*/
public void begin(String namespace, String name, Attributes attributes)
throws Exception {
begin(attributes);
}
/**
* This method is called when the body of a matching XML element
* is encountered. If the element has no body, this method is
* not called at all.
*
* @param text The text of the body of this element
* @deprecated Use the {@link #body(String,String,String) body} method
* with <code>namespace</code> and <code>name</code> parameters
* instead.
*/
@Deprecated
public void body(String text) throws Exception {
// The default implementation does nothing
}
/**
* This method is called when the body of a matching XML element is
* encountered. If the element has no body, this method is not called at
* all. The default implementation delegates to the deprecated method
* {@link #body(String) body} without the <code>namespace</code> and
* <code>name</code> parameters, to retain backwards compatibility.
*
* @param namespace the namespace URI of the matching element, or an
* empty string if the parser is not namespace aware or the element has
* no namespace
* @param name the local name if the parser is namespace aware, or just
* the element name otherwise
* @param text The text of the body of this element
* @since Digester 1.4
*/
public void body(String namespace, String name, String text)
throws Exception {
body(text);
}
/**
* This method is called when the end of a matching XML element
* is encountered.
*
* @deprecated Use the {@link #end(String,String) end} method with
* <code>namespace</code> and <code>name</code> parameters instead.
*/
@Deprecated
public void end() throws Exception {
// The default implementation does nothing
}
/**
* This method is called when the end of a matching XML element
* is encountered. The default implementation delegates to the deprecated
* method {@link #end end} without the
* <code>namespace</code> and <code>name</code> parameters, to retain
* backwards compatibility.
*
* @param namespace the namespace URI of the matching element, or an
* empty string if the parser is not namespace aware or the element has
* no namespace
* @param name the local name if the parser is namespace aware, or just
* the element name otherwise
* @since Digester 1.4
*/
public void end(String namespace, String name)
throws Exception {
end();
}
/**
* This method is called after all parsing methods have been
* called, to allow Rules to remove temporary data.
*/
public void finish() throws Exception {
// The default implementation does nothing
}
}
主要四个方法 begin 、body、end、finish
而对于元素的处理便会先进行rule的选取,然后对每个rule进行上面四个方法的处理,例如:addObjectCreate的方法实现为
public void addObjectCreate(String pattern, String className,
String attributeName) {
addRule(pattern,
new ObjectCreateRule(className, attributeName));
}
当对SERVER元素进行addObjectCreate的时候实际上等于是给SERVER添加了一个RULE,那么整个处理过程为怎么回事呢,首先贴出Digester类中中startElement方法(只贴出主要部分)
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);
} 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 + "'.");
}
}
可以看出实际上处理元素开始就是筛选处理的元素的对应的RULE,进行begin方法的调用
而endElement方法思路也基本是这样只不过是调用了RULE的body和end方法,而finish()方法是当XML文档reader完成后进行调用。并且当在startElement方法中调用RULE的时候是按照添加RULE的先后顺序进行调用,EndElement方法则是想法的顺序进行调用,谁让xml就是这么个规则。
最后挑选其中的一个RULE的子类(具体实现类)的代码分析,当然有N个这样的子类,下面贴出ObjectCreateRule的部分代码,也就是当调用Digester.addObjectCreate方法后添加的RULE
首先贴出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);
}
可以看出其中的逻辑为如果有classname这个属性的话,那么这个对象instance的时候 要进行子类的instance,并且把instance的对象方法stack中,digester.push方法实际上就是放入Digester类的stack字段中,而整个Digester对类的操作都是在stack中进行的,当然这个原因也是xml的规则所决定的。
那么贴出ObjectCreateRule的end代码
public void end(String namespace, String name) throws Exception {
Object top = digester.pop();
if (digester.log.isDebugEnabled()) {
digester.log.debug("[ObjectCreateRule]{" + digester.match +
"} Pop " + top.getClass().getName());
}
}
可以看出instance进行了出栈操作
当然还有其他很多的RULE,比如属性赋值,添加child等等。当然既然知道了RULE的实现也可以自我定制自我的RULE。