一般来说,语句按一定规则进行推导后会形成一个语法树,这种树状结构有利于对语句结构层次的描述。同样Jasper对JSP语法解析后也会生成一棵树,这棵树各个节点包含了不同的信息,但对于JSP来说解析后的语法树比较简单,只有一个父节点和n个子节点。例如node1是表示形如<!-- 字符串 -->的注释节点,节点里面包含了一个表示注释字符串的属性;而node2则可能是表示形如<%= a+b %>的表达式节点,节点里面包含一个表示表达式的属性,同样地其他节点可能表示JSP的其他语法,有了这棵树我们就可以很方便地生成对应的Servlet。
现在看看怎样解析生成这棵树的,
①首先定义树数据结构,其中parent指向父节点,nodes是此节点的子节点,且nodes应该是有序的列表,这样能保证与解析顺序一致。另外由于每个节点的属性不同,Node类只提供公共的部分属性,对于不同节点其他属性需要继承Node额外实现。
public class Node {
private Node parent;
private List<Node> nodes;
private String text;
private Attributes attrs;
}
public class RootNode{}
public class CommentNode{}
public class PageNode{}
public class IncludeNode{}
public class TaglibNode{}
②其次需要一个读取JSP文件的工具类,此工具类主要提供对JSP文件的字符操作,其中有个cursor变量用于表示目前解析位置,主要的方法则包括判断是否到达文件末尾的hasMoreInput方法,获取下个字符的nextChar方法,获取某个范围内的字符组成的字符串getText方法,匹配是否包含某字符串的matches方法,跳过空格符的skipSpaces方法,以及跳转到某个字符串的skipUntil方法。有了这些辅助操作就可以开始读取解析语法了。
public class JspReader{
private int cursor;
public int getCursor(){ return cursor ; }
boolean hasMoreInput(){...}
public int nextChar(){...}
public String getText(int start,int end){...}
boolean matches(String string){...}
int skipSpaces(){...}
int skipUntil(String limit){...}
}
③需要一个JSP语法解析器对JSP进行解析,这里为了简单说明只解析<!-- .... -->注释语法、<@page .../%>页面指令、<%@include.../%>包含指令、<%@taglib.../%>标签指令。假设对index.jsp进行语法解析,匹配到<%--则表示注释语法,获取其中的注释文字并创建commentNode节点作为根节点的子节点,如果匹配到<%@则有三种可能,所以需要进一步解析,即对应页面指令、包含指令和标签指令等的解析。最后解析出来的就是如图所示的一棵语法树。
public class Parser{
public RootNode parse(){
JspReader reader = new JspReader("index.jsp");
RootNode root = new RootNode();
while (reader.hasMoreInput()) {
if (reader.matches("<%--")) {
int start = reader.getCursor();
reader.skipUntil("--%>");
int end = reader.getCursor();
CommentNode commentNode = new CommentNode ();
commentNode.setText(reader.getText(start, stop));
commentNode.setParent(parent);
parent.getList().add(commentNode);
} else if (reader.matches("<%@")) {
if (reader.matches("page")) {
解析<%@page.../%>里面的属性生成attrs
PageNode pageNode = new PageNode ();
pageNode.setAttributes(attrs);
pageNode.setParent(parent);
parent.getList().add(pageNode);
} else if (reader.matches("include")) {
解析<%@include.../%>里面的属性生成attrs
IncludeNode includeNode = new IncludeNode ();
includeNode.setAttributes(attrs);
includeNode.setParent(parent);
parent.getList().add(includeNode);
} else if (reader.matches("taglib")) {
解析<%@taglib.../%>里面的属性生成attrs
TaglibNode taglibNode = new TaglibNode ();
taglibNode.setAttributes(attrs);
taglibNode.setParent(parent);
parent.getList().add(taglibNode);
}
}
}
return root;
}
}