一个用dom编写的目录树形结构,请大家提提意见。

03-08-26 jander
目录可以在任何层次添加、删除。

category.dtd

<?xml version="1.0"  encoding="GBK"?>
<!ELEMENT category ( category*)>
<!ATTLIST category
          id   ID  REQUIRED
          name  CDATA  REQUIRED
          locked (true|false) "false"
          disvisible (true|false) "false"
          level    CDATA  REQUIRED
>
<p>

category.xml

<?xml version="1.0"  encoding="GBK"?>
<!DOCTYPE category SYSTEM "category.dtd">
<category id="c0" name="category0" locked="false" disvisible="false" level="0">
    <category id="c1" name="category1" locked="false" disvisible="false" level="1"/>
</category>
<p>

CategoryDetail

import java.util.List;

public class CategoryDetail {
    private String id;
    private String name;
    private boolean locked;
    private boolean disvisible;
    private int level;
    private List parentList;//所有父亲的集合,按继承顺序排列。
    private List childList;//所有孩子的集合

    public CategoryDetail(String id, String name, boolean locked, boolean disvisible, int level, List parentList, List childList) {
        this.id = id;
        this.name = name;
        this.locked = locked;
        this.disvisible = disvisible;
        this.level = level;
        this.parentList = parentList;
        this.childList = childList;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isLocked() {
        return locked;
    }

    public void setLocked(boolean locked) {
        this.locked = locked;
    }

    public boolean isDisvisible() {
        return disvisible;
    }

    public void setDisvisible(boolean disvisible) {
        this.disvisible = disvisible;
    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public List getParentList() {
        return parentList;
    }

    public void setParentList(List parentList) {
        this.parentList = parentList;
    }

    public List getChildList() {
        return childList;
    }

    public void setChildList(List childList) {
        this.childList = childList;
    }

    public String printTag(int count,String tag){
        StringBuffer sb=new StringBuffer();
        for(int i=0;i<count;i++){
            sb.append(tag);
        }
        return sb.toString();
    }

}

<p>

CategoryData

public class CategoryData {
    public static CategoryData Empty=new CategoryData();
    private String id;
    private String name;
    private boolean locked;
    private boolean disvisible;
    private int level;

    public CategoryData() {
    }

    public CategoryData(String id, String name, boolean locked, boolean disvisible, int level) {
        this.id = id;
        this.name = name;
        this.locked = locked;
        this.disvisible = disvisible;
        this.level = level;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isLocked() {
        return locked;
    }

    public void setLocked(boolean locked) {
        this.locked = locked;
    }

    public boolean isDisvisible() {
        return disvisible;
    }

    public void setDisvisible(boolean disvisible) {
        this.disvisible = disvisible;
    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public String toString() {
        return "CategoryData: id="+id+"  name="+name;
    }
}

<p>

CategoryTree

import org.w3c.dom.*;

import javax.xml.parsers.*;
import java.io.*;
import java.util.*;

public class CategoryTree {
    private Document doc;
    private String xmlFile = "D:\\myapp\\xmltree\\build\\category.xml";
    private final static String ID_ATTR = "id";
    private final static String NAME_ATTR = "name";
    private final static String LOCKED_ATTR = "locked";
    private final static String DISVISIBLE_ATTR = "disvisible";
    private final static String LEVEL_ATTR = "level";
    private final static String CATEGORY_ELEMENT = "category";

    public CategoryTree() {
        load();
    }

    public CategoryDetail getCategoryDetail(String id) throws CategoryNotFoundException {
        Element element = doc.getElementById(id);
        if (element == null)
            throw new CategoryNotFoundException();
        return new CategoryDetail(
                id,
                element.getAttribute(NAME_ATTR),
                Boolean.getBoolean(element.getAttribute(LOCKED_ATTR)),
                Boolean.getBoolean(element.getAttribute(DISVISIBLE_ATTR)),
                Integer.parseInt(element.getAttribute(LEVEL_ATTR)),
                getParentList(element),
                getChildList(element)
        );
    }

    public CategoryData getCategoryData(String id) throws CategoryNotFoundException {
        Element element = doc.getElementById(id);
        if (element == null)
            throw new CategoryNotFoundException();
        else
            return new CategoryData(
                    id,
                    element.getAttribute(NAME_ATTR),
                    Boolean.getBoolean(element.getAttribute(LOCKED_ATTR)),
                    Boolean.getBoolean(element.getAttribute(DISVISIBLE_ATTR)),
                    Integer.parseInt(element.getAttribute(LEVEL_ATTR))
            );
    }

    public void createCategory(String name, String parentID) throws CategoryNotFoundException {
        Element parent = doc.getElementById(parentID);
        if (parent == null)
            throw new CategoryNotFoundException();
        int parentLevel = Integer.parseInt(parent.getAttribute(LEVEL_ATTR));
        Element element = doc.createElement(CATEGORY_ELEMENT);
//测试时,用时间作ID.
        element.setAttribute(ID_ATTR, "c" + String.valueOf(System.currentTimeMillis()));
        element.setAttribute(NAME_ATTR, name);
        element.setAttribute(LOCKED_ATTR, "true");
        element.setAttribute(DISVISIBLE_ATTR, "true");
        element.setAttribute(LEVEL_ATTR, String.valueOf(++parentLevel));
        parent.appendChild(element);
        store();
    }

    public void removeCategory(String id) throws CategoryNotFoundException {
        Element element = doc.getElementById(id);
        if (element == null)
            throw new CategoryNotFoundException();
        Node parent = element.getParentNode();
        parent.removeChild(element);

        store();
    }

    private void load() {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setValidating(true);
            factory.setNamespaceAware(false);
            factory.setIgnoringElementContentWhitespace(true);
            DocumentBuilder builder = factory.newDocumentBuilder();
            doc = builder.parse(new File(xmlFile));
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("can not load xml resource.");
        }
    }

    private void store() {
        try {
            //实现一个DOMSerializer类,来存储xml。
            DOMSerializer serializer = new DOMSerializer("GBK");
            serializer.serialize(doc, new File(xmlFile));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private List getChildList(Element element) {
        List childList = new ArrayList();
        NodeList nodeList = element.getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element child = (Element) node;
                childList.add(
                        new CategoryData(
                                child.getAttribute(ID_ATTR),
                                child.getAttribute(NAME_ATTR),
                                Boolean.getBoolean(child.getAttribute(LOCKED_ATTR)),
                                Boolean.getBoolean(child.getAttribute(DISVISIBLE_ATTR)),
                                Integer.parseInt(child.getAttribute(LEVEL_ATTR))
                        )
                );
            }
        }
        return childList;
    }

    private List getParentList(Element element) throws CategoryNotFoundException {
        int level = Integer.parseInt(element.getAttribute("level"));
        LinkedList parentList = new LinkedList();
        Element tmp = null;
        for (int i = 0; i < level; i++) {
            tmp = (Element) element.getParentNode();
            parentList.addFirst(getCategoryData(tmp.getAttribute("id")));
            element = tmp;
        }
        return parentList;
    }

    public static void main(String[] args) throws Exception {

        CategoryTree tree = new CategoryTree();
        long start = System.currentTimeMillis();
        tree.createCategory("我的文档", "c0");
        tree.removeCategory("c3");
        CategoryDetail c = tree.getCategoryDetail("c0");


        Iterator iter = c.getChildList().iterator();
        while (iter.hasNext()) {
            System.out.println(iter.next());
        }

        long end = System.currentTimeMillis() - start;
        System.out.println("run :" + end + " ms");
    }
}
<p>

neuhawk
2003-08-26 18:00
应该跟用户权限结合起来。

比如权限分配,只能由administrator看见。

jander
2003-08-26 18:13
这只是一个简单的演示。

如果要加权限,可以直接在可以加上readRole,addRole,adminRole等属性,就可以了。

jander
2003-08-26 22:00
感觉用dom解析,速度慢了点,占内存。

还是应该用数据库来产生目录的xml文档。然后在页面格式化显示xml文档的速度快。

banq
2003-08-27 08:58
非常不错

XML实现树形结构有其优势,但是很多情况下,我们并不需要知道整个树形结构,因为整个树形结构显示出来也许非常复杂,一般只关系某个层次的父子、兄弟关系。

树形结构比较麻烦的是数据库节点实现和前台页面节点管理相结合。

使用数据库节点管理的好处是可以接受非常大的树结构数据。

节点如何和资源挂钩,也是一个比较麻烦的事情。

neuhawk
2003-08-27 15:14
好像jspsmartmenu也是根据xml生成的吧。

我现在的开发的系统就是用数据库的,我想改成xml的。

robbin
2003-08-27 15:58
你的程序最好不要用File IO来读写硬盘文件,这样你必须在程序里面写死一个绝对路径名称,一旦换台机器部署,就必须修改源代码。改用Classloader来查找文件,例如:

FileInputStream fin = getClass().getClassLoader().getResourceAsStream("/category.xml");
<p>

这样,只要在CLASSPATH下的文件,就一定会被搜索到。

其实我不明白你为什么要用DOM来操纵XML,如果改用dom4j,很简单的几行的代码就可以了,完全不需要这么麻烦。

说到性能,用DOM来操纵XML,一方面取决于使用的XML Parser的性能,另一方面取决于API的性能,JDK自带的Crimson的性能很差,已经被Apache的XML项目小组淘汰掉了,如果改用Xerces2,性能会高很多,这需要配置一下JRE\lib\jaxp.properties文件。

推荐一篇关于Java XML API的性能和易用性的很棒的文章:

http://www-900.ibm.com/developerWorks/cn/xml//x-injava/index.shtml

http://www-900.ibm.com/developerWorks/cn/xml/x-injava2/index.shtml

neuhawk
2003-08-27 16:26
用jdom也很简单吧,而且网上资料也很多。

robbin
2003-08-27 17:23
你看看我给出的URL连接,jdom的性能奇差。jdom不论性能还是实现的功能都无法和dom4j想比,有趣的是,连Sun发布的jaxm也使用了dom4j。

magician
2003-08-27 17:39
指出一点小小的问题

FileInputStream fin = getClass().getClassLoader().getResourceAsStream("/category.xml");

这个方法会根据容器的不同实现有不同的反应

最好在自己对其classloader比较熟悉的容器上使用,以避免不必要的麻烦

robbin
2003-08-27 18:43
嗯,确实应该稍微注意,不过问题也不大。因为ClassLoader继承是有层次的,只要你把xml只放到系统环境变量CLASSPATH指定的路径下,由App ClassLoader来搜索,那么不管什么容器都不会有问题了。

uyang
2003-08-27 19:45
用jaxb好了

neuhawk
2003-08-27 21:56
在实际开发中,那些模块常用xml?

xuejm1225
2003-10-13 15:01
利用DOM来解析XML的话需要考虑到数据文件的大小。当XML文件在1兆以上的时候DOM的性能将会急剧的下降。

这也是为什么SAX/SAX2能够得到广泛使用的原因之一了。

crogers
2003-10-14 08:42
FileInputStream fin = getClass().getClassLoader().getResourceAsStream("/category.xml");

其实也不见得好

既然都有需要经常改变的菜单了

自然这个系统就有自己的配置文件,配置文件指明路径就可以了

至于配置文件在哪,大可以写进web.xml,如struts的web.xml配置一样

对了,我们这里也是用xml来维护一个菜单文件的,比较长了,有简单的权限等。建议如果不是做通用系统,还是实现一个适合自己的就好了

猜你喜欢
2Go 1 2 下一页