最近有一个任务是将项目中的一些资源代码转化成是可配置的,因此,心里想到了使用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!