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://m.tkk7.com/Files/sitinspring/TagPersistenceSample.java20071219145515.rar