欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SAX 解析大型XML文件

程序员文章站 2022-01-20 10:05:59
...

最近在项目中需要把一些系统配置表导到XML文件中,一开始觉得数据量不大,使用dom4j就可以了,后来才发现数据量超出预期的大小,程序很快就内存溢出了。SAX在顺序遍历XML所有节点时,还是有很大的优势的。下面是我写的SAX解析XML的代码,解析大型XML文件来说性能比较好。

DefaultElementHandler.java

 

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public abstract class DefaultElementHandler extends DefaultHandler{

	//入栈标志
	private boolean begin;
	//节点名称
	private String tagName;
	//内容缓冲区
	private StringBuilder sb;

	//带节点名称的构造方法
	public DefaultElementHandler(String tagName) {
		this.tagName = tagName;
		this.begin = false;
		this.sb = new StringBuilder();
	}

	/**
	 * 处理节点开始
	 */
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		if (qName.equals(tagName) || begin) {
			sb.append("<");
			sb.append(qName);
			sb.append(" ");
			int attrCount = attributes.getLength();
			for(int i=0;i<attrCount;i++){
				sb.append(attributes.getQName(i));
				sb.append("=\"");
				sb.append(attributes.getValue(i));
				sb.append("\" ");
			}
			sb.append(">");
			begin = true;
		}
	}

	/**
	 * 处理节点内容
	 */
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		String text = new String(ch, start, length);
		if (text.trim().equals(""))
			return;
		if (begin) 
			sb.append(text);
	}

	/**
	 * 处理节点结束
	 */
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		String stag = "</" + tagName + ">";
		String ntag = "</" + qName + ">";
		if (stag.equals(ntag) || begin) {
			sb.append(ntag);
			if (stag.equals(ntag)) {
				begin = false;
				try {
					Document doc = DocumentHelper.parseText(sb.toString());
					Element element = doc.getRootElement();
					this.processElement(element);
				} catch (DocumentException e) {
					e.printStackTrace();
				}
				sb.setLength(0);
			}
		}
	}

	/**
	 * 对节点进行操作
	 * @param element
	 */
	public abstract void processElement(Element element);

}

 SAXReadXML

 

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.dom4j.Element;


public class SAXReadXML {

	/**
	 * @param args
	 * @throws Exception 
	 * @throws  
	 */
	public static void main(String[] args) throws  Exception {
		SAXParserFactory sf = SAXParserFactory.newInstance();
		SAXParser sax = sf.newSAXParser();
		//"TABLE"是需要处理的节点
		sax.parse("d:\\myxml.xml", new DefaultElementHandler("TABLE"){
			@Override
			public void processElement(Element element) {
				//这里获得了每一个"TABLE"节点,在这里做具体的操作。
				System.out.println(element.asXML());
			}
		}); 
	}

}

 

用这段程序解析1GB的XML文件都不会出现内存溢出,而且同时拥有dom4j对节点处理的方便性。

myxml.xml

<?xml version="1.0" encoding="UTF-8"?>
<TABLES>
  <TABLE>
    <ID>ID0</ID>
    <NAME>NAME0</NAME>
    <VALUE>VALUE0</VALUE>
    <DESC>DESC0</DESC>
    <COLUMNS>
      <COLUMN>
        <C1>C10</C1>
        <C2>C20</C2>
        <C3>C30</C3>
      </COLUMN>
      <COLUMN>
        <C1>C10</C1>
        <C2>C20</C2>
        <C3>C30</C3>
      </COLUMN>
    </COLUMNS>
  </TABLE>
  <TABLE>
    <ID>ID1</ID>
    <NAME>NAME1</NAME>
    <VALUE>VALUE1</VALUE>
    <DESC>DESC1</DESC>
    <COLUMNS>
      <COLUMN>
        <C1>C11</C1>
        <C2>C21</C2>
        <C3>C31</C3>
      </COLUMN>
      <COLUMN>
        <C1>C11</C1>
        <C2>C21</C2>
        <C3>C31</C3>
      </COLUMN>
    </COLUMNS>
  </TABLE>
  <TABLE>
    <ID>ID2</ID>
    <NAME>NAME2</NAME>
    <VALUE>VALUE2</VALUE>
    <DESC>DESC2</DESC>
    <COLUMNS>
      <COLUMN>
        <C1>C12</C1>
        <C2>C22</C2>
        <C3>C32</C3>
      </COLUMN>
      <COLUMN>
        <C1>C12</C1>
        <C2>C22</C2>
        <C3>C32</C3>
      </COLUMN>
    </COLUMNS>
  </TABLE>
</TABLES>

 

相关标签: XML