最近有一个任务是将项目中的一些资源代码转化成是可配置的,因此,心里想到了使用XML文件来配置,虽然最后使用了properties来配置,但是突然想自己读取一把xml文件,并且不借助jdom之类的jar包来解析
想到xml配置文件是一个循环结构,因此最开始想使用递归方法,但是到后来觉得递归找子项不太好找(不想记录尖括号位置那种写法),后来觉得用数据结构里面建立树的写法来建立"xml 树",我觉得这种思路是对的,因为即使是html标准的文档也会使用domtree的概念,而且一些解析xml的jar 包最后得到的也是近似是树的结构。
我只是做了一个很小的测试,今天北京雾霾特别大,头昏脑涨的,也就没有考虑过多复杂的情形,以下面的xml为例做测试
<school>
<colleage>
<student>
<name>luchi</name>
<sex>male</sex>
</student>
<student>
<name>lushuiye</name>
<sex>female</sex>
</student>
<student>
<name>zhangsan</name>
<sex>male</sex>
</student>
</colleage>
<gate>
<color>red</color>
<text>welcome to graduate school</text>
</gate>
</school>
我把每个尖括号都看作是一个类(等同于C语言的结构体),有其属性,特别是有parent和child这两个属性,类如下:
package test;
import java.util.HashSet;
import java.util.Set;
public class Node {
private String name;
private String value;
private Set<Node> child=new HashSet<Node>();
private Node parent=null;
public Node getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Set<Node> getChild() {
return child;
}
public void setChild(Set<Node> child) {
this.child = child;
}
}
把类的对象看作是树的节点,有子女和孩子,我的处理逻辑是读取标签,如果遇到<>标签就简历一个新的树节点,如果遇到文本则更新当前节点的属性值,如果遇到结束标签,则将当前节点设置成当前节点的父节点(退一个节点),然后继续扫面文档,直到文档结束
具体代码如下
package test;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
public class ReadXML {
String path="C:\\Users\\dell\\Desktop\\test.xml";
String text="";
//根节点
Node root=new Node();
//设置当前节点为空,当前节点就是这棵树最新构造的节点
Node currentNode=null;
//读取内容并解析
public void parse() throws IOException{
File xmlFile=new File(path);
InputStream in=new FileInputStream(xmlFile);
int len;
byte []buff=new byte[1024];
while((len=in.read(buff))>0){
text+=new String(buff);
}
root.setParent(null);
parseText(root,text);
}
/*解析的主要方法
*
* @param root 传入的根节点
* @param text 传入的文本
* @author luchi
*/
private void parseText(Node root,String text) {
currentNode=root;
//看是不是第一次构造根节点
boolean isFirst=true;
while(!text.trim().equals("")){
//处理开始标签
if(text.startsWith("<")&& !text.startsWith("</")){
int head_begin=text.indexOf("<");
int head_end=text.indexOf(">");
String name=text.substring(head_begin+1,head_end);
if(currentNode.getParent()==null && isFirst){
currentNode.setName(name);
isFirst=false;
}else{
Node child=new Node();
child.setName(name);
child.setParent(currentNode);
currentNode.getChild().add(child);
currentNode=child;
// System.out.println(" "+currentNode.getName());
}
text=text.substring(head_end+1).trim();
continue;
}else if(!text.startsWith("</") && !text.startsWith("<")){ //处理正文属性标签
int head_begin=text.indexOf("</");
String value=text.substring(0,head_begin).trim();
currentNode.setValue(value);
text=text.substring(head_begin).trim();
continue;
}else if(text.startsWith("</")){ //处理结尾标签,回溯节点
Node temp=currentNode.getParent();
if(temp!=null){
currentNode=temp;
}
int end_end=text.indexOf(">");
text=text.substring(end_end+1).trim();
continue;
}
}
}
public void printGivenNumBlank(int blank){
for(int i=0;i<blank;i++){
System.out.print(" ");
}
}
//深度遍历结果
public void show(Node srcNode,int blank){
if(srcNode!=null){
printGivenNumBlank(blank);
System.out.print(srcNode.getName());
if(srcNode.getValue()!=null && !srcNode.getValue().equals("")){
System.out.print(" "+srcNode.getValue());
}
System.out.println();
for(Node child:srcNode.getChild()){
show(child,blank*2);
}
}
}
public void result(){
show(root,5);
}
}
代码注释差不多写清楚了,最后我们来看一下测试程序
@Test
public void testXML() throws IOException {
ReadXML parser=new ReadXML();
parser.parse();
parser.result();
}
以及该结果
school
gate
text welcome to graduate school
color red
colleage
student
sex male
name zhangsan
student
name luchi
sex male
student
sex female
name lushuiye
如图所示打印出了一个横过来的xml树,说明处理成功,今天人比较疲倦,逻辑比较简单,也没有涉及到复杂的xml格式等情况,就到这里,over!