场景
XML
文件作为默认utf8
格式的文件,它的作用和JSON
文件相当。比如可以做为简单的数据存储格式,配置文件,网站的sitemap.xml
导航等。它比json
强的一点是它还有样式描述文件dtd
,可以实现让XML
里的结构化数据显示表格样式。
xml
<?xml version="1.0" encoding="UTF-8"?>
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>
说明
- 和
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;
- 流式读取使用
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;
}
例子
- 以下是读取
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()+"");
}
}
}