编写了一些从html文本创建文本树的类,放在这里方便查找
将html树化,需要创建节点结构和标签结构对应
查找每个标签的起止位置,创建节点,并创建其内部的子节点。在创建的过程中记录节点的属性、内部文本
节点需要提供丰富、方便的方法,否则树化的意义不大。要像js那样提供查找子节点、获取属性、获取内部文本等方法。
TreeBuilder 通过html文本创建实例。通过build方法建立树结构,返回根节点
package treeer;
import util.StringUtil;
/**将html文本树化*/
public class TreeBuilder {
String src;
StringUtil stringUtil;
public TreeBuilder(String src){
this.src=src;
stringUtil=new StringUtil(src);
}
public Node build(){
Node node=new Node();
node.name="root";
findNodes(0,src.length(),node);
return node;
}
public void findNodes(int start,int end,Node parent){
int tagEnd=start;
while (tagEnd!=-1&&tagEnd<end){
start=stringUtil.findNext('<',tagEnd,true);
if(start==-1||start>=end)break;
tagEnd=findNode(start,parent);
if(tagEnd==0)break;
}
}
/**找到标签的结尾位置
* @param start 标签的开始位置
* @return 标签的结束位置*/
public int findNode(int start,Node parent){
int afterStart=stringUtil.findNoSpace(start);
Node node=new Node();
int end;
int matchPair = stringUtil.findMatchPair(start);
int nameEnd=stringUtil.findNext(' ',start,true);
if(nameEnd==-1||nameEnd>matchPair)nameEnd=matchPair;
String name;
int attrEnd=matchPair;
int beforeMatchPair = stringUtil.findBackNoSpace(matchPair);
if(src.charAt(beforeMatchPair)=='/'){
//</>形式的标签
end=matchPair+1;
attrEnd=beforeMatchPair;
if(nameEnd==matchPair)nameEnd=beforeMatchPair;
name=src.substring(afterStart,nameEnd);;
}else {
//<></>形式的标签
name=src.substring(afterStart,nameEnd);
int findStart=matchPair;
//可能嵌套了相同名称的子标签
int sameNameSonCount=0;
while (true){
int endTagStart=stringUtil.findNext('<',findStart,true);
if (endTagStart==-1){
//找不到对应的</>,返回<>的结束位置
return matchPair+1;
}
int afterEndTagStart=stringUtil.findNoSpace(endTagStart);
if(src.charAt(afterEndTagStart)!='/'){
//不是结束标签
if (src.startsWith(name,afterEndTagStart))sameNameSonCount++;
findStart=afterEndTagStart;
continue;
}
int endTagContent= stringUtil.findNoSpace(afterEndTagStart);
if(src.startsWith(name, endTagContent)){
if(sameNameSonCount==0){
end=stringUtil.findNext('>',endTagContent,true)+1;
//标签内文字
String inside=src.substring(matchPair+1,endTagStart);
node.inside=inside;
findNodes(matchPair+1,endTagStart,node);
break;
}else {
sameNameSonCount--;
}
}
findStart=endTagContent;
}
}
String attrText=null;
if(attrEnd>nameEnd+1)
attrText=src.substring(nameEnd+1,attrEnd);
node.name=name;
node.src=src.substring(start,end);
analyseAttrForNode(node,attrText);
parent.addSon(node);
return end;
}
private void analyseAttrForNode(Node node,String attrText){
if(attrText==null||attrText.equals(""))return;
StringUtil attrStringUtil=new StringUtil(attrText);
int attrStart=0;
int attrEnd=0;
while (attrEnd<attrText.length()) {
int assertSign = attrStringUtil.findNext('=', attrStart, true);
if (assertSign == -1) return;//没有属性
attrEnd = attrStringUtil.findNext(' ', assertSign, true);
if (attrEnd == -1) attrEnd = attrText.length();
String name = attrText.substring(attrStart, assertSign);
String value = attrText.substring(assertSign + 1, attrEnd);
Attr attr=new Attr(name,value)