[Java]_[初级]_[以SAX流的方式高效读取XML大文件]

场景

  1. XML文件作为默认utf8格式的文件,它的作用和JSON文件相当。比如可以做为简单的数据存储格式,配置文件,网站的sitemap.xml导航等。它比json强的一点是它还有样式描述文件dtd,可以实现让XML里的结构化数据显示表格样式。
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
  1. sitemap.xml作为网站的站点地图,提供了固定的格式化数据, 也方便了搜索引擎进行索引。 因此对sitemap.xml的读写功能是比较重要的。那么如何实现大数据量的XML读写才可以节省内存和减少指令的执行?
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
  xmlns:xhtml="http://www.w3.org/1999/xhtml">
	<url>
	<loc>https://blog.csdn.net/infoworld</loc>
	<priority>1.0</priority>
	<lastmod>2023-07-28</lastmod>
	<changefreq>Daily</changefreq>
	</url>
</urlset>

说明

  1. JSON一样,对XML读用流的方式,可以减少中间的DOM模型的生成,也不需要读取整个XML文件到内存。这样的API不需要借助第三方库,Java标准库里就有。
java 复制代码
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
  1. 流式读取使用SAX模型的方式,从开头按起始标签和结束标签的方式进行读取数据。并需要实现自己的Handler来处理需要的元素。这个Handler就是模板类,它的相关方法会在识别到XML特定的对象是调用,比如属性,起始结束元素,元素值等。
java 复制代码
public boolean readAll(File file){

	SAXParserFactory sf = SAXParserFactory.newInstance();
	boolean result = false;
	try {
	    SAXParser sp = sf.newSAXParser();
	    sp.parse(file,this);
	    logger.info(sitemaps.size()+"");
	    result = true;
	} catch (ParserConfigurationException e) {
	    logger.error(e.getMessage());
	} catch (SAXException e) {
	    logger.error(e.getMessage());
	} catch (IOException e) {
	    logger.error(e.getMessage());
	}

	return result;
}

例子

  1. 以下是读取sitemap.xml文件的Reader实现,Sitemap对象实际就是Map对象。

SitemapReader

java 复制代码
import Sitemap;
import org.apache.log4j.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class SitemapReader extends DefaultHandler {

    private static Logger logger = Logger.getLogger(SitemapReader.class);

    private ArrayList<Sitemap> sitemaps = new ArrayList<>();
    private Sitemap current;
    private String cPValue;
    private String cPName;

    /**
     * 重置Reader,可以再次读取
     */
    public void reset(){
        sitemaps.clear();
        cPName = null;
        cPValue = null;
        current = null;
    }

    /**
     *
     * @return 读取到的sitemaps;
     */
    public List<Sitemap> getSitemaps(){
        return sitemaps;
    }

    /**
     *
     * @param file
     * @return
     */
    public boolean readAll(File file){
        SAXParserFactory sf = SAXParserFactory.newInstance();
        boolean result = false;
        try {
            SAXParser sp = sf.newSAXParser();
            sp.parse(file,this);
            logger.info(sitemaps.size()+"");
            result = true;
        } catch (ParserConfigurationException e) {
            logger.error(e.getMessage());
        } catch (SAXException e) {
            logger.error(e.getMessage());
        } catch (IOException e) {
            logger.error(e.getMessage());
        }

        return result;
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        if(cPName != null && current != null) {
            cPValue = new String(ch, start, length);
            current.put(cPName,cPValue);
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        cPName = null;
        cPValue = null;

        switch(qName) {
            case "url": {
                sitemaps.add(current);
                current = null;
                break;
            }
        }
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

        cPName = null;
        cPValue = null;

        switch(qName){
            case "url":{
                current = new Sitemap();
                break;
            }
            default:
                cPName = qName;
        }
    }
}

TestSitemapReader

java 复制代码
import Sitemap;
import SitemapReader;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.io.File;
import java.net.URL;
import java.util.List;
import java.util.logging.Logger;

@RunWith(JUnit4.class)
public class TestSitemapReader{

    Logger logger = Logger.getLogger(TestSitemapReader.class.getName());

    @Test
    public void testXmlSaxReader(){
        URL resource = this.getClass().getResource("/");
        String path = resource.getPath();

        File file = new File(path+"..\\..\\..\\..\\doc\\tests\\xml\\sitemap.xml");
        SitemapReader sr = new SitemapReader();
        if(sr.readAll(file)){
            List<Sitemap> sitemaps = sr.getSitemaps();
            logger.info(sitemaps.size()+"");
        }

    }
}

参考

  1. SAX方式读取XML文件

  2. SAXParser

相关推荐
坐吃山猪4 小时前
SpringBoot01-配置文件
java·开发语言
我叫汪枫5 小时前
《Java餐厅的待客之道:BIO, NIO, AIO三种服务模式的进化》
java·开发语言·nio
yaoxtao5 小时前
java.nio.file.InvalidPathException异常
java·linux·ubuntu
Swift社区6 小时前
从 JDK 1.8 切换到 JDK 21 时遇到 NoProviderFoundException 该如何解决?
java·开发语言
DKPT7 小时前
JVM中如何调优新生代和老生代?
java·jvm·笔记·学习·spring
phltxy7 小时前
JVM——Java虚拟机学习
java·jvm·学习
seabirdssss9 小时前
使用Spring Boot DevTools快速重启功能
java·spring boot·后端
喂完待续9 小时前
【序列晋升】29 Spring Cloud Task 微服务架构下的轻量级任务调度框架
java·spring·spring cloud·云原生·架构·big data·序列晋升
benben0449 小时前
ReAct模式解读
java·ai