Dom4j节点处理器的实现
 
Dom4j为XML文档解析提供了强大的API支持,在实际开发中,为了处理方便,常常以节点元素(Element)为单位进行处理,并且结合数据库和Java技术,为节点生成ID属性。这样,就很有必要在Dom4j的基础上,重新封装一些适用需要的方法,以提高开发效率。下面是我利用业余时间做的一个Dom4j节点处理器工具类的实现。希望能节省开发人员宝贵时间。
 
说明:为了写起来方便,可以单独运行,我没有写单独的测试类,实际用的时候,删除掉测试main()和test()方法即可。
 
注释很详细,不用废话了。下面是处理器的实现:
 
测试用的xml:
输出三个测试对象
----------srcXml------------
<?xml version="1.0" encoding="GBK"?>
<doc>
    <person>
        <name>某人</name>
        <adds>
            <add ID="10001">
                <BS>10001</BS>
                <note>郑州市经三路</note>
            </add>
            <add ID="10002">
                <BS>10002</BS>
                <note>西安市太白路</note>
            </add>
            <add ID="">
                <BS>10002</BS>
                <note>空ID节点啊</note>
            </add>
            <add>
                <BS>10002</BS>
                <note>空ID节点啊</note>
            </add>
        </adds>
    </person>
    <other>
        <name ID="HEHE">ASDF</name>
        <name>空ID节点啊</name>
        <name>空ID节点啊</name>
    </other>
</doc>
----------nodeXml1------------
<?xml version="1.0" encoding="GBK"?>
<doc>
    <person>
        <name>某人</name>
        <adds>
            <add ID="10001">
                <BS>10001</BS>
                <note>郑州市经三路</note>
            </add>
            <add ID="10002">
                <BS>10002</BS>
                <note>西安市太白路</note>
            </add>
            <add ID="">
                <BS>10002</BS>
                <note>空ID节点啊</note>
            </add>
            <add>
                <BS>10002</BS>
                <note>空ID节点啊</note>
            </add>
        </adds>
    </person>
    <other>
        <name ID="HEHE">ASDF</name>
        <name>空ID节点啊</name>
        <name>空ID节点啊</name>
    </other>
</doc>
----------nodeXml2------------
<?xml version="1.0" encoding="GBK"?>
<doc>
    <person>
        <name>某人</name>
        <adds>
            <add ID="10001">
                <BS>10001</BS>
                <note>郑州市经三路</note>
            </add>
            <add ID="10002">
                <BS>10002</BS>
                <note>西安市太白路</note>
            </add>
            <add ID="">
                <BS>10002</BS>
                <note>空ID节点啊</note>
            </add>
            <add>
                <BS>10002</BS>
                <note>空ID节点啊</note>
            </add>
        </adds>
    </person>
    <other>
        <name ID="HEHE">ASDF</name>
        <name>空ID节点啊</name>
        <name>空ID节点啊</name>
    </other>
</doc>
 
处理器的实现类:
package com.topsoft.icib.common.utils;

import org.dom4j.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.lang.StringUtils;

import java.util.Random;
import java.util.Iterator;
import java.util.ArrayList;

/**
* Created by IntelliJ IDEA.<br>
* <b>User</b>: leizhimin<br>
* <b>Date</b>: 2008-3-27 18:42:39<br>
* <b>Note</b>: XML节点处理器,包含XML元素的CRUD方法。
*/

public class XmlNodeHandler {
    private static Log log = LogFactory.getLog(XmlNodeHandler.class);

    /**
     * 在xml的指定位置插入一个元素
     *
     * @param srcXml  原xml
     * @param nodeXml 元素xml
     * @param xpath   要插入元素父节点的位置
     * @return 原xml插入节点后的完整xml文档
     */

    public static String addElement(String srcXml, String nodeXml, String xpath) {
        String resultXml = null;
        try {
            Document docSrc = DocumentHelper.parseText(srcXml);
            Document docNode = DocumentHelper.parseText(nodeXml);
            Element parentElement = (Element) docSrc.getRootElement().selectSingleNode(xpath);
            parentElement.add(docNode.getRootElement());
            resultXml = docSrc.asXML();
        } catch (DocumentException e) {
            log.error("在文档" + xpath + "位置添加新节点发生异常,请检查!");
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        return resultXml;
    }

    /**
     * 删除xml文档中指定ID的元素
     *
     * @param srcXml    原xml
     * @param xmlNodeId 元素ID属性值
     * @return 删除元素后的xml文档
     */

    public static String removeElementById(String srcXml, String xmlNodeId) {
        String resultXml = null;
        try {
            Document docSrc = DocumentHelper.parseText(srcXml);
            Element removeElement = docSrc.getRootElement().elementByID(xmlNodeId);
            removeElement.detach();  //直接删除自己
//            removeElement.getParent().remove(removeElement);  //从父节点删除子节点
            resultXml = docSrc.asXML();
        } catch (DocumentException e) {
            log.error("删除文档中ID为" + xmlNodeId + "的节点发生异常,请检查!");
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        return resultXml;
    }

    /**
     * 删除xml文档中以xpath为直接父节点的ID属性为空的子节点,ID属性为空包括值为空、空串、或者ID属性不存在。
     *
     * @param srcXml 原xml文档
     * @param xpath  要删除空节点的所在父节点的xpath
     * @return 删除空节点后的xml文档
     */

    public static String removeNullIdElement(String srcXml, String xpath) {
        String resultXml = null;
        try {
            Document srcDoc = DocumentHelper.parseText(srcXml);
            removeNullIdElement(srcDoc, xpath);
            resultXml = srcDoc.asXML();
        } catch (DocumentException e) {
            log.error("在" + xpath + "下删除空节点发生异常,请检查xpath是否正确!");
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        return resultXml;
    }

    /**
     * 删除xml文档中以xpath为直接父节点的ID属性为空的子节点,ID属性为空包括值为空、空串、或者ID属性不存在。
     *
     * @param srcDoc 原xml的Document对象
     * @param xpath  要删除空节点的所在父节点的xpath
     * @return 删除空节点后的xml文档
     */

    public static Document removeNullIdElement(Document srcDoc, String xpath) {
        Node parentNode = srcDoc.getRootElement().selectSingleNode(xpath);
        if (!(parentNode instanceof Element)) {
            log.error("所传入的xpath不是Elementpath,删除空节点失败!");
        } else {
            int i = 0;
            for (Iterator<Element> it = ((Element) parentNode).elementIterator(); it.hasNext();) {
                Element element = it.next();
                if (element.attribute("ID") == null) {
                    element.detach();
                    i++;
                } else {
                    if (StringUtils.isBlank(element.attribute("ID").getValue())) {             
                            element.detach();
                            i++;
                     }
                }
            }
            log.info("在" + xpath + "下成功删除" + i + "了个空节点!");
        }
        return srcDoc;
    }

    /**
     * 删除xml文档中指定xpath路径下所有直接子节点为空的节点
     *
     * @param srcXml    原xml文档
     * @param xpathList xpaht列表
     * @return 删除空节点后的xml文档
     */

    public static String removeAllNullIdElement(String srcXml, ArrayList<String> xpathList) {
        String resultXml = null;
        try {
            Document srcDoc = DocumentHelper.parseText(srcXml);
            for (Iterator<String> it = xpathList.iterator(); it.hasNext();) {
                String xpath = it.next();
                removeNullIdElement(srcDoc, xpath);
            }
            resultXml = srcDoc.asXML();
        } catch (DocumentException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        return resultXml;
    }

    /**
     * 更新xml文档中指定ID的元素,ID保持不变
     *
     * @param srcXml     原xml
     * @param newNodeXml 新xml节点
     * @param xmlNodeId  更新元素ID属性值
     * @return 更新元素后的xml文档
     */

    public static String updateElementById(String srcXml, String newNodeXml, String xmlNodeId) {
        String resultXml = null;
        try {
            Document docSrc = DocumentHelper.parseText(srcXml);
            Document newDocNode = DocumentHelper.parseText(newNodeXml);
            //获取要更新的目标节点
            Element updatedNode = docSrc.elementByID(xmlNodeId);
            //获取更新目标节点的父节点
            Element parentUpNode = updatedNode.getParent();
            //删除掉要更新的节点
            parentUpNode.remove(updatedNode);

            //获取新节点的根节点(作为写入节点)
            Element newRoot = newDocNode.getRootElement();
            //处理新节点的ID属性值和BS子元素的值
            if (newRoot.attribute("ID") == null) {
                newRoot.addAttribute("ID", xmlNodeId);
            } else {
                newRoot.attribute("ID").setValue(xmlNodeId);
            }
            //在原文档中更新位置写入新节点
            parentUpNode.add(newRoot);
            resultXml = docSrc.asXML();
        } catch (DocumentException e) {
            log.error("更新xml文档中ID为" + xmlNodeId + "节点发生异常,请检查!");
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        return resultXml;
    }

    /**
     * 更新xml文档中指定ID的元素,并检查ID和BS,加以设置
     *
     * @param srcXml     原xml
     * @param newNodeXml 新xml节点
     * @param xmlNodeId  更新元素ID属性值
     * @return 更新元素后的xml文档
     */

    public static String updateElementByIdAddIdBs(String srcXml, String newNodeXml, String xmlNodeId) {
        String resultXml = null;
        try {
            Document docSrc = DocumentHelper.parseText(srcXml);
            Document newDocNode = DocumentHelper.parseText(newNodeXml);
            //获取要更新的目标节点
            Element updatedNode = docSrc.elementByID(xmlNodeId);
            //获取更新目标节点的父节点
            Element parentUpNode = updatedNode.getParent();
            //删除掉要更新的节点
            parentUpNode.remove(updatedNode);

            //获取新节点的根节点(作为写入节点)
            Element newRoot = newDocNode.getRootElement();
            //处理新节点的ID属性值和BS子元素的值
            if (newRoot.attribute("ID") == null) {
                newRoot.addAttribute("ID", xmlNodeId);
            } else {
                newRoot.attribute("ID").setValue(xmlNodeId);
            }
            if (newRoot.element("BS") == null) {
                newRoot.addElement("BS", xmlNodeId);
            } else {
                newRoot.element("BS").setText(xmlNodeId);
            }
            //在原文档中更新位置写入新节点
            parentUpNode.add(newRoot);
            resultXml = docSrc.asXML();
        } catch (DocumentException e) {
            log.error("更新xml文档中ID为" + xmlNodeId + "节点发生异常,请检查!");
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        return resultXml;
    }

    /**
     * 为xml元素设置ID属性
     *
     * @param xmlElement 原xml元素
     * @return 设置id后的xml串
     */

    public static String addIdAttribute(String xmlElement) {
        String resultXml = null;
        try {
            Document srcDoc = DocumentHelper.parseText(xmlElement);
            Element root = srcDoc.getRootElement();
//            Long nextValue = SequenceUtils.getSequeceNextValue();
            Long nextValue = new Random().nextLong();
            root.addAttribute("ID", nextValue.toString());
            resultXml = root.asXML();
        } catch (DocumentException e) {
            log.error("给xml元素设置ID属性发生异常,请检查!");
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        return resultXml;
    }

    /**
     * 为xml元素设置ID属性,并将此属性写入一个指定子节点文本值域
     *
     * @param xmlElement 原xml元素
     * @param nodeName   (直接)子节点的名称,或相对当前节点的xpath路径
     * @return 设置id和子节点后的xml串
     */

    public static String addIdAndWriteNode(String xmlElement, String nodeName) {
        String resultXml = null;
        try {
            Document srcDoc = DocumentHelper.parseText(xmlElement);
            Element root = srcDoc.getRootElement();
//            Long nextValue = SequenceUtils.getSequeceNextValue();
            Long nextValue = new Random().nextLong();
            root.addAttribute("ID", nextValue.toString());
            Node bsElement = root.selectSingleNode(nodeName);
            if (bsElement instanceof Element && bsElement != null) {
                bsElement.setText(nextValue.toString());
            } else {
                root.addElement(nodeName).setText(nextValue.toString());
            }
            resultXml = root.asXML();
        } catch (DocumentException e) {
            log.error("给xml元素设置ID属性和直接" + nodeName + "子元素值时发生异常,请检查!");
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        return resultXml;
    }


    public static void main(String args[]) {
        test();
    }

    public static void test() {
        System.out.println("----------test()----------");
        String srcXml = "<?xml version=\"1.0\" encoding=\"GBK\"?>\n" +
                "<doc>\n" +
                "    <person>\n" +
                "        <name>某人</name>\n" +
                "        <adds>\n" +
                "            <add ID=\"10001\">\n" +
                "                <BS>10001</BS>\n" +
                "                <note>郑州市经三路</note>\n" +
                "            </add>\n" +
                "            <add ID=\"10002\">\n" +
                "                <BS>10002</BS>\n" +
                "                <note>西安市太白路</note>\n" +
                "            </add>\n" +
                "            <add ID=\"\">\n" +
                "                <BS>10002</BS>\n" +
                "                <note>空ID节点啊</note>\n" +
                "            </add>\n" +
                "            <add>\n" +
                "                <BS>10002</BS>\n" +
                "                <note>空ID节点啊</note>\n" +
                "            </add>\n" +
                "        </adds>\n" +
                "    </person>\n" +
                "    <other>\n" +
                "        <name ID=\"HEHE\">ASDF</name>\n" +
                "        <name>空ID节点啊</name>\n" +
                "        <name>空ID节点啊</name>\n" +
                "    </other>\n" +
                "</doc>";
        String nodeXml1 = "            <add >\n" +
                "                <BS></BS>\n" +
                "                <note>西安市太白路1</note>\n" +
                "            </add>";

        String nodeXml2 = "            <add>\n" +
                "                <note>西安市太白路2</note>\n" +
                "            </add>";

//        System.out.println("输出三个测试对象");
//        System.out.println("----------srcXml------------");
//        System.out.println(srcXml);
//        System.out.println("----------nodeXml1------------");
//        System.out.println(srcXml);
//        System.out.println("----------nodeXml2------------");
//        System.out.println(srcXml);

        System.out.println("----------addElement()测试----------");
        String addrs = addElement(srcXml, nodeXml1, "/doc/person/adds");
        System.out.println(addrs);

        System.out.println("----------addIdAttribute()测试----------");
        String addIdrs = addIdAttribute(nodeXml1);
        System.out.println(addIdrs);

        System.out.println("----------addIdAndWriteNode()测试----------");
        String addIdNoders = addIdAndWriteNode(nodeXml1, "BS");
        System.out.println(addIdNoders);

        System.out.println("----------removeElementById()测试----------");
        String removeIdrs = removeElementById(srcXml, "10001");
        System.out.println(removeIdrs);

        System.out.println("----------updateElementByIdAddIdBs()测试----------");
        String upbyidrs = updateElementByIdAddIdBs(srcXml, nodeXml2, "10001");
        System.out.println(upbyidrs);

        System.out.println("----------updateElementById()测试----------");
        String upbyidrs1 = updateElementById(srcXml, nodeXml2, "10001");
        System.out.println(upbyidrs1);

        System.out.println("----------removeNullIdElement()测试----------");
        String rvnullrs = removeNullIdElement(srcXml, "/doc/person/adds");
        System.out.println(rvnullrs);

        System.out.println("----------removeAllNullIdElement()测试----------");
        ArrayList<String> xpathList = new ArrayList<String>();
        xpathList.add("/doc/person/adds");
        xpathList.add("/doc/other");
        String rvallnullrs = removeAllNullIdElement(srcXml, xpathList);
        System.out.println(rvallnullrs);

        System.out.println("----------Dom4j生成一个xml测试----------");
        Document doc = DocumentHelper.createDocument();
        doc.addElement("root")
                .addElement("person").setText("haha:)");
        System.out.println(doc.asXML());
    }
}
 
运行结果:
 
----------test()----------
----------addElement()测试----------
<?xml version="1.0" encoding="GBK"?>
<doc>
    <person>
        <name>某人</name>
        <adds>
            <add ID="10001">
                <BS>10001</BS>
                <note>郑州市经三路</note>
            </add>
            <add ID="10002">
                <BS>10002</BS>
                <note>西安市太白路</note>
            </add>
            <add ID="">
                <BS>10002</BS>
                <note>空ID节点啊</note>
            </add>
            <add>
                <BS>10002</BS>
                <note>空ID节点啊</note>
            </add>
        <add>
                <BS/>
                <note>西安市太白路1</note>
            </add></adds>
    </person>
    <other>
        <name ID="HEHE">ASDF</name>
        <name>空ID节点啊</name>
        <name>空ID节点啊</name>
    </other>
</doc>
----------addIdAttribute()测试----------
<add ID="7549173897283584063">
                <BS/>
                <note>西安市太白路1</note>
            </add>
----------addIdAndWriteNode()测试----------
<add ID="8974292836389323633">
                <BS>8974292836389323633</BS>
                <note>西安市太白路1</note>
            </add>
----------removeElementById()测试----------
<?xml version="1.0" encoding="GBK"?>
<doc>
    <person>
        <name>某人</name>
        <adds>
            
            <add ID="10002">
                <BS>10002</BS>
                <note>西安市太白路</note>
            </add>
            <add ID="">
                <BS>10002</BS>
                <note>空ID节点啊</note>
            </add>
            <add>
                <BS>10002</BS>
                <note>空ID节点啊</note>
            </add>
        </adds>
    </person>
    <other>
        <name ID="HEHE">ASDF</name>
        <name>空ID节点啊</name>
        <name>空ID节点啊</name>
    </other>
</doc>
----------updateElementByIdAddIdBs()测试----------
<?xml version="1.0" encoding="GBK"?>
<doc>
    <person>
        <name>某人</name>
        <adds>
            
            <add ID="10002">
                <BS>10002</BS>
                <note>西安市太白路</note>
            </add>
            <add ID="">
                <BS>10002</BS>
                <note>空ID节点啊</note>
            </add>
            <add>
                <BS>10002</BS>
                <note>空ID节点啊</note>
            </add>
        <add ID="10001">
                <note>西安市太白路2</note>
            <BS xmlns="10001"/></add></adds>
    </person>
    <other>
        <name ID="HEHE">ASDF</name>
        <name>空ID节点啊</name>
        <name>空ID节点啊</name>
    </other>
</doc>
----------updateElementById()测试----------
<?xml version="1.0" encoding="GBK"?>
<doc>
    <person>
        <name>某人</name>
        <adds>
            
            <add ID="10002">
                <BS>10002</BS>
                <note>西安市太白路</note>
            </add>
            <add ID="">
                <BS>10002</BS>
                <note>空ID节点啊</note>
            </add>
            <add>
                <BS>10002</BS>
                <note>空ID节点啊</note>
            </add>
        <add ID="10001">
                <note>西安市太白路2</note>
            </add></adds>
    </person>
    <other>
        <name ID="HEHE">ASDF</name>
        <name>空ID节点啊</name>
        <name>空ID节点啊</name>
    </other>
</doc>
----------removeNullIdElement()测试----------
16:17:32,689  INFO XmlNodeHandler:113 - 在/doc/person/adds下成功删除4了个空节点!
<?xml version="1.0" encoding="GBK"?>
<doc>
    <person>
        <name>某人</name>
        <adds>
            <add ID="10001">
                <BS>10001</BS>
                <note>郑州市经三路</note>
            </add>
            <add ID="10002">
                <BS>10002</BS>
                <note>西安市太白路</note>
            </add>
            
            
        </adds>
    </person>
    <other>
        <name ID="HEHE">ASDF</name>
        <name>空ID节点啊</name>
        <name>空ID节点啊</name>
    </other>
</doc>
----------removeAllNullIdElement()测试----------
16:17:32,705  INFO XmlNodeHandler:113 - 在/doc/person/adds下成功删除4了个空节点!
16:17:32,705  INFO XmlNodeHandler:113 - 在/doc/other下成功删除3了个空节点!
<?xml version="1.0" encoding="GBK"?>
<doc>
    <person>
        <name>某人</name>
        <adds>
            <add ID="10001">
                <BS>10001</BS>
                <note>郑州市经三路</note>
            </add>
            <add ID="10002">
                <BS>10002</BS>
                <note>西安市太白路</note>
            </add>
            
            
        </adds>
    </person>
    <other>
        <name ID="HEHE">ASDF</name>
        
        
    </other>
</doc>
----------Dom4j生成一个xml测试----------
<?xml version="1.0" encoding="UTF-8"?>
<root><person>haha:)</person></root>

Process finished with exit code 0
 
程序中尽量避免用Dom4j之外的第三方类库,但是还用到了,可以修改一下:
1、用到Log4j的地方,可以修改log对象的实现为Java中的Logger工具:
      private static Logger log = Logger.getLogger(XmlNodeHandler.class.getName());

2、用到apache的beanutils工具包中的StringUtils.isBlank()方法时候,可以改用JDK API String中的equel()方法做比较进行替换。具体操作很简单,我就不写了。

3、用到Sequence生成的Id的地方,我都改为java.util.Random类来实现,目的还是为了把眼光放到Dom的处理上。如果有博友对这个SequenceUtils工具类有兴趣,我可以把代码贴出去。

本处理器工具类涵盖Dom4j最常用部分80%以上的API。放到以方便查看。

衷心祝福广大支持和浏览熔岩博客的朋友们:周末愉快!!!

 
在最后奉献出我亲手制作的CHM格式的“Dom4j-1.6.1 API文档”。