sitinspring原创,转载请注明作者及出处.
树状结构是生活中常见的数据结构,如公司等级,军队等级,类别归属,标签结构都是树状结构的具体例子,如何将树状结构持久化和从持久化中取出对于使用关系型数据库的应用一直比较麻烦,不如DB4O这样的数据库直接存取这样简单.本人用XML文件模拟关系型数据库,实现了树状结构存入文件及从文件中取出的完整功能,对为树状结构存取头疼的程序员有一定参考价值.
例中使用的数据结构为标签结构,如Java包括J2EE和J2SE,J2EE包括JSp,EJB等,j2se包括swing,awt,applet等.
代码如下:
标签类,它能组成树状结构 :
package com.sitinspring;

import java.util.ArrayList;
import java.util.List;


/** *//**
* 标签类
*
* @author sitinspring
*
* @date 2007-12-19
*/

public class Tag
{
// ID
private String id;

// 父Tag的ID
private String parentId;

// 标签名
private String name;

// 其下的标签集合
private List<Tag> childTags;

// 父Tag
private Tag parentTag;
// 四空格表示一个缩进
private static final String TAB = " ";


/** *//**
* 构造函数
*
* @param name
*/

public Tag(String name)
{
this.name = name;
id = IdUtil.getId();
parentId = IdUtil.getDefaultId();
parentTag = null;
}

/** *//**
* 构造函数
* @param id
* @param parentId
* @param name
*/

public Tag(String id,String parentId,String name)
{
this.id = id;
this.parentId = parentId;
this.name = name;
parentTag = null;
}


/** *//**
* 添加一个Tag
*/

public void add(Tag tag)
{

if (childTags == null)
{
childTags = new ArrayList<Tag>();
}

// 设置被添加Tag的父ID和父Tag
tag.parentId = this.id;
tag.parentTag = this;

// 将tag添加进链表
childTags.add(tag);
}


/** *//**
* 从链表中删除一个Tag
*/

public void remove(Tag tag)
{

if (childTags.contains(tag))
{
// 重置被添加Tag的父ID和父Tag
tag.parentId = IdUtil.getDefaultId();
tag.parentTag = null;

// 将tag从链表中删除
childTags.remove(tag);
}
}

public String toString()
{
return " Tag名=" + name + " path=" + getPath()+ " id=" + id+ " parentId=" + parentId;
}

/** *//**
* 打印单位信息,包括其下包括的单位
*/

public void printInfo(String tabs)
{
// 输出本身的信息
System.out.println(tabs + this.toString());

// 对链表进行检查

if (childTags == null)
{
return;
}

// 将链表的Tag集合中的Tag信息也打印出来

for (Tag tag : childTags)
{
// tabs + TAB是让下到一层目录就缩进一次
tag.printInfo(tabs + TAB);
}
}

/** *//**
* 取得Tag的绝对路径
*/

private String getPath()
{
StringBuffer sb = new StringBuffer();

Tag tagPointer = parentTag;


if (parentTag == null)
{
return "";
}

while (tagPointer != null)
{
// 取得的单位名放置在前方
sb.insert(0, tagPointer.name + "/");

// 继续向上回溯
tagPointer = tagPointer.parentTag;
}

return sb.toString();
}

/** *//**
* 将一个Tag下的所有Tag全取出来,存放到allTags中
* @param allTags
*/

public void findAllTags(List<Tag> allTags)
{
allTags.add(this);
// 对链表进行检查

if (childTags == null || childTags.size()==0)
{
return;
}

// 将链表的Tag集合中的Tag信息也一起递归取出来

for (Tag tagTmp : childTags)
{
tagTmp.findAllTags(allTags);
}
}


public Tag getParentTag()
{
return parentTag;
}


public String getName()
{
return name;
}


public String getParentId()
{
return parentId;
}


public void setParentId(String parentId)
{
this.parentId = parentId;
}


public String getId()
{
return id;
}


public void setParentTag(Tag parentTag)
{
this.parentTag = parentTag;
}
}
制作ID的工具类:
package com.sitinspring;


/** *//**
* 制作ID的工具类
* @author sitinspring
*
* @date 2007-12-19
*/

public final class IdUtil
{
private static int index=1;

/** *//**
* 私有构造函数,防止生成实例
*
*/

private IdUtil()
{
}

/** *//**
* 用最简单的ID生成机制生成ID,仅为例子.
* @return
*/

public synchronized static String getId()
{
String retval=String.valueOf(index);
index++;
return retval;
}

/** *//**
* 取得缺省ID
* @return
*/

public static String getDefaultId()
{
return "0";
}
}
将Tag从XML中读取存入的持久类:
package com.sitinspring;

import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;


/** *//**
* 将Tag从XML中读取存入的持久类 春有百花秋有月 夏有凉风冬有雪 若无些事挂心头 便是人间好时节
*
* @author sitinspring
*
* @date 2007-12-19
*/

public class XmlPersistence
{
// XML文件路径名
private static final String xmlFile = "tags.xml";


/** *//**
* 将Tag存入XML文件
*
* @param tag
*/

public void saveTag(Tag tag)
{

try
{
Document document = null;


if ((new File(xmlFile).exists()))
{
// 文件存在则读取document
SAXReader reader = new SAXReader();
document = reader.read(new File(xmlFile));

} else
{
// 文件不存在则创建document
String text = "<tags></tags>";
document = DocumentHelper.parseText(text);
}

Element root = document.getRootElement();

// 取出tag下的所有子Tag
List<Tag> allTags = new ArrayList<Tag>();
tag.findAllTags(allTags);


for (Tag tagTmp : allTags)
{
Element tagElm = root.addElement("tag");
Element idElm=tagElm.addElement("id");
idElm.setText(tagTmp.getId());

Element parentIdElm=tagElm.addElement("parentId");
parentIdElm.setText(tagTmp.getParentId());
Element nameElm=tagElm.addElement("name");
nameElm.setText(tagTmp.getName());
}

writeDocumentToFile(document);

} catch (Exception ex)
{
ex.printStackTrace();
}
}


/** *//**
* 将Tag从XML文件中取出
*
* @param id
*/

public Tag fetchTagById(String id)
{

try
{
Document document = null;


if ((new File(xmlFile).exists()))
{
// 文件存在则读取document
SAXReader reader = new SAXReader();
document = reader.read(new File(xmlFile));

} else
{
// 文件不存在则返回空
return null;
}

// tag列表
List<Tag> tags=new ArrayList<Tag>();
// 遍历XML文档,取出元素放入tag列表
Element root = document.getRootElement();
List tagElms=root.elements("tag");

for(Iterator it=tagElms.iterator();it.hasNext();)
{
Element elm=(Element)it.next();
Tag tag=new Tag(elm.elementText("id"),elm.elementText("parentId"),elm.elementText("name"));
tags.add(tag);
}
// 建立tag之间的级联关系

for(Tag tag:tags)
{
setupTagRelationship(tag,tags);
}
// 找出tagID为输入参数的返回

for(Tag tag:tags)
{

if(tag.getId().equals(id))
{
return tag;
}
}

} catch (Exception ex)
{
ex.printStackTrace();
}

return null;
}

/** *//**
* 建立tag之间的级联关系
* @param tag
* @param tags
*/

private void setupTagRelationship(Tag tag,List<Tag> tags)
{

for (Tag tagTmp : tags)
{

if( tagTmp!=tag && tagTmp.getParentId().equals(tag.getId()))
{
tag.add(tagTmp);
//tagTmp.setParentTag(tag);
}
}
}


/** *//**
* 将Document写入文件
*
* @param document
*/

private void writeDocumentToFile(Document document)
{

try
{
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("GBK"); // 指定XML编码

XMLWriter writer = new XMLWriter(new FileWriter(xmlFile), format);
writer.write(document);
writer.close();

} catch (Exception ex)
{
ex.printStackTrace();
}
}
}
测试代码:
package com.sitinspring;


/** *//**
* 测试类
* @author sitinspring
*
* @date 2007-12-19
*/

public class Main
{

public static void main(String[] args)
{
// 建立Tag树
Tag ejbTag=new Tag("EJB");
Tag jspTag=new Tag("JSP");
Tag j2eeTag=new Tag("J2EE");
j2eeTag.add(ejbTag);
j2eeTag.add(jspTag);
Tag awtTag=new Tag("awt");
Tag appletTag=new Tag("applet");
Tag swingTag=new Tag("swing");
Tag j2seTag=new Tag("J2SE");
j2seTag.add(awtTag);
j2seTag.add(appletTag);
j2seTag.add(swingTag);
Tag javaTag=new Tag("Java");
javaTag.add(j2eeTag);
javaTag.add(j2seTag);
System.out.println("打印建立好的根节点信息");
javaTag.printInfo("");
// 将Tag树存入XML文件
XmlPersistence persistence=new XmlPersistence();
persistence.saveTag(javaTag);
// 取出tag树并打印信息
String id=javaTag.getId();
Tag tagFetched=persistence.fetchTagById(id);
System.out.println("取出整颗树信息为");
tagFetched.printInfo("");
id=j2seTag.getId();
System.out.println("取出部分树信息为");
persistence.fetchTagById(id).printInfo("");
}
}
测试结果:
打印建立好的根节点信息
Tag名=Java path= id=8 parentId=0
Tag名=J2EE path=Java/ id=3 parentId=8
Tag名=EJB path=Java/J2EE/ id=1 parentId=3
Tag名=JSP path=Java/J2EE/ id=2 parentId=3
Tag名=J2SE path=Java/ id=7 parentId=8
Tag名=awt path=Java/J2SE/ id=4 parentId=7
Tag名=applet path=Java/J2SE/ id=5 parentId=7
Tag名=swing path=Java/J2SE/ id=6 parentId=7
取出整颗树信息为
Tag名=Java path= id=8 parentId=0
Tag名=J2EE path=Java/ id=3 parentId=8
Tag名=EJB path=Java/J2EE/ id=1 parentId=3
Tag名=JSP path=Java/J2EE/ id=2 parentId=3
Tag名=J2SE path=Java/ id=7 parentId=8
Tag名=awt path=Java/J2SE/ id=4 parentId=7
Tag名=applet path=Java/J2SE/ id=5 parentId=7
Tag名=swing path=Java/J2SE/ id=6 parentId=7
取出部分树信息为
Tag名=J2SE path=Java/ id=7 parentId=8
Tag名=awt path=Java/J2SE/ id=4 parentId=7
Tag名=applet path=Java/J2SE/ id=5 parentId=7
Tag名=swing path=Java/J2SE/ id=6 parentId=7

代码下载:
http://www.blogjava.net/Files/sitinspring/TagPersistenceSample.java20071219145515.rar