参考了这篇
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若干个属性