Dom4j 解析大容量xml(ElementHandler使用)

参考了这篇

https://blog.csdn.net/mark_lq/article/details/45040731

dom4j本身提供了两种解析xml的方式:dom解析和sax解析。关于dom解析和sax解析各自的优缺点这里不再多述,只强调的一点是由于越来越多的应用会遇到大数据场景,SAX解析方式刚好是解决此类场景的完美方案,因此“DOM4J解析大数据的方案”就是"如何利用SAX方式解析大数据的方案"(当然JAXP中的sax解析也是同样的方案)


XML的解析方式:
 1.DOM(Document Object Model 文档对象模型)
 关键字:树(Document)
 优点: 把xml文件在内存中构造树形结构,可以遍历和修改节点
 缺点: 如果文件比较大,内存有压力,解析的时间会比较长
2. SAX(Simple API for Xml 基于XML的简单API)
 关键字:流(Stream)
 把xml文件作为输入流,触发标记开始,内容开始,标记结束等动作
 优点: 解析可以立即开始,速度快,没有内存压力

 缺点: 不能对节点做修改


由于xml文件很大,所以使用sax方式比较好。

(当然,又找到了另一个解析xml的工具,叫做VTD,蛮好用的,大家可以去了解一下https://vtd-xml.sourceforge.io)


————————————————————————————————————————————————————————



具体代码:

建一个Springboot的项目,引入相关的dom4j(1.6.1),jdbc,mysql,spring-data-jpa,lombok(节省代码量,很好用)的包

/**
 * 
 */
package com.demo.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @description 
 * @author naka
 * @date 2018年4月6日 下午11:57:48
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Role implements Serializable{
    private static final long serialVersionUID = 3926276668667517847L;
    @Id
    @GeneratedValue
    private Integer id;
    
    @Column
    private String name;
    
    @Column
    private String descr;
}
/**
 * 
 */
package com.demo.model;

import org.springframework.data.jpa.repository.JpaRepository;

/**
 * @description 
 * @author naka
 * @date 2018年4月7日 上午12:12:39
 */
public interface RoleRepository extends JpaRepository{
}

按网上的写法是写一个类实现ElementHandler

/**
 * 
 */
package com.demo.parseXML;

import java.util.Date;
import java.util.Iterator;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.ElementHandler;
import org.dom4j.ElementPath;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.demo.model.Role;
import com.demo.model.RoleRepository;
import com.demo.model.User;
import com.demo.model.UserManager;

/**
 * @description 定制的事件处理器  
 * @author naka
 * @date 2018年4月9日 下午2:44:10
 */
public class OrderElementHandler implements ElementHandler{
    
    @Autowired
    private RoleRepository roleRepository; 
    

    /**
     * 将Element节点数据保存到数据库
     * 
     * @param element
     *            遍历XML文档时的当前节点
     * @return
     */
    public boolean saveUser(Element element){
        Role role = new Role();
        role.setName(element.attributeValue("order-no"));
        role.setDescr(element.elementText("order-date"));
        Role result = roleRepository.saveAndFlush(role);
        System.out.println(result);
        return true;
    }


    public void onEnd(ElementPath arg0){
        Element row = arg0.getCurrent();
        Element rowSet = row.getParent();
        Document document = row.getDocument();
        Element root = document.getRootElement();
        Iterator it = root.elementIterator();
        while (it.hasNext()){
            Element element = (Element) it.next();
            System.out.println(" order-no : " + element.attributeValue("order-no") + " order-date : " + element.elementText("order-date"));
            saveUser(element);

        }
        row.detach();
    }

    public void onStart(ElementPath path){

    }
}
/**
 * 
 */
package com.demo.model;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import com.demo.parseXML.OrderElementHandler;

/**
 * @description
 * @author naka
 * @date 2018年4月9日 下午2:56:01
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class Dom4jTest{

    /**
     * 从xml文件中读取数据,并将数据写入db
     * 
     * @param filePath
     *            xml文件的存放路径
     * @return
     */
    public boolean readXML(String filePath){
        OrderElementHandler orderElementHandler = new OrderElementHandler();
        SAXReader reader = new SAXReader();
        reader.addHandler("/orders/order", orderElementHandler);

        Document document = null;
        try{
            File file = new File(filePath);
            document = reader.read(file);
        }catch (DocumentException e){
            e.printStackTrace();
            return false;
        }
        return true;
    }

    
    @Test
    public void testRead(){
        XMLReader reader = null;
        long startTime = System.currentTimeMillis();
        
        readXML("D://orders.xml");
        
        long endTime = System.currentTimeMillis();
        System.out.println(" is end! the millis is : " + (endTime - startTime));
    }
    
    
}
OrderElementHandler orderElementHandler = new OrderElementHandler();
SAXReader reader = new SAXReader();
reader.addHandler("/orders/order", orderElementHandler);

这种写法如果在onEnd中不涉及到bean的注入,是没有问题的。

涉及bean的注入时,由于OrderElementHandler是new出来的,那么它里面的@Autowired其实都是无效的。

所以很简单,这种情况,直接写在test类中就好了。如下改写:

/**
 * 
 */
package com.demo.model;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.ElementHandler;
import org.dom4j.ElementPath;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

/**
 * @description
 * @author naka
 * @date 2018年4月9日 下午2:56:01
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class Dom4jTest{
    
    @Autowired
    private RoleRepository roleRepository;
    
    /**
     * 将Element节点数据保存到数据库
     * 
     * @param element
     *            遍历XML文档时的当前节点
     * @param mdbName
     *            数据库名称 含路径
     * @return
     */
    public boolean saveUser(Element element){
        Role role = new Role();
        role.setName(element.attributeValue("order-no"));
        role.setDescr(element.elementText("order-date"));
        Role result = roleRepository.saveAndFlush(role);
        System.out.println(result);
        return true;
    }

   

    /**
     * 从xml文件中读取数据,并将数据写入db
     * 
     * @param filePath
     *            xml文件的存放路径
     * @return
     */
    public boolean readXML(String filePath){
//        OrderElementHandler orderElementHandler = new OrderElementHandler();
        SAXReader reader = new SAXReader();
        reader.addHandler("/orders/order", new ElementHandler(){
            
            
            @Override
            public void onStart(ElementPath elementPath){
            }
            
            @Override
            public void onEnd(ElementPath elementPath){
                Element row = elementPath.getCurrent();
                Element rowSet = row.getParent();
                Document document = row.getDocument();
                Element root = document.getRootElement();
                Iterator it = root.elementIterator();
                while (it.hasNext()){
                    Element element = (Element) it.next();
                    System.out.println(" order-no : " + element.attributeValue("order-no") + " order-date : " + element.elementText("order-date"));
                    saveUser(element);
                }
                row.detach();
                
            }
        });
        
        Document document = null;
        try{
            File file = new File(filePath);
            document = reader.read(file);
        }catch (DocumentException e){
            e.printStackTrace();
            return false;
        }
        return true;
    }

    
    @Test
    public void testRead(){
        XMLReader reader = null;
        long startTime = System.currentTimeMillis();
        
        readXML("D://orders.xml");
        
        long endTime = System.currentTimeMillis();
        System.out.println(" is end! the millis is : " + (endTime - startTime));
    }
    
    
    
}

我们的XML格式这样



    
        2017-12-21T03:31:28.000Z
        xxxxxxxxx若干个属性


     2017-12-21T03:31:28.000Z
        xxxxxxxxx若干个属性

 

你可能感兴趣的:(Dom4j 解析大容量xml(ElementHandler使用))