dom解析占用内存大(我这边需要解析各种各样的kml文件,有时4-5M的kml文件使用dom解析很多手机就内存溢出了),也需要引入第三方库,所以使用相对于节省内存很多、不需引入其他库的sax解析就是很好的选择了。因为sax解析比较复杂的xml文件特别麻烦,所以整理了一个简化android sax解析的工具。
实现思路:和Android Touch事件传递机制一样,把需要子解析器解析的节点往下传递。
如果有进一步简化的方法,欢迎交流!email:csqwyyx@163.com。
示例程序:https://github.com/John-Chen/EasySaxParser
简化工具SaxParser:
public abstract class SaxParser {
protected String curQName;
protected StringBuilder curValue = new StringBuilder();
protected SaxParser saxParser;
protected String saxParserQName;
/**
* 需要生成子SaxParser的节点名称
*/
protected HashSet<String> childParserQNames;
public SaxParser() {
}
public SaxParser(HashSet<String> childParserQNames) {
this.childParserQNames = childParserQNames;
}
protected void startElement(String uri, String localName, String qName, Attributes attributes) {
if(qName == null){
return;
}
if(saxParser != null){
saxParser.startElement(uri, qName, qName, attributes);
}else if(childParserQNames != null && childParserQNames.contains(qName)){
this.saxParser = dispatchTo(qName, attributes);
if(this.saxParser != null){
this.saxParserQName = qName;
saxParser.parserStart(attributes);
}
}else{
curQName = qName;
if(curValue.length() > 0){
curValue.delete(0, curValue.length());
}
}
}
protected void endElement(String uri, String localName, String qName) {
if(qName == null){
return;
}
if(qName.equals(saxParserQName)){
if(saxParser != null){
saxParser.parserEnd();
}
saxParser = null;
saxParserQName = null;
}else if(saxParser != null){
saxParser.endElement(uri, qName, qName);
}else{
parserElementEnd(qName, curValue.toString());
curQName = null;
if(curValue.length() > 0){
curValue.delete(0, curValue.length());
}
}
}
protected void characters(char[] ch, int start, int length) {
if(saxParser != null){
saxParser.characters(ch, start, length);
}else{
String data = new String(ch, start, length);
if(data.length() > 0 && curQName != null){
curValue.append(data);
}
}
}
/**
* 开始解析一个输入流
* @param is 文件输入流
* @param rootParserQName 解析的文件根节点
* @param rootParser 根解析器
*/
public static void start(InputStream is,
final String rootParserQName,
final SaxParser rootParser){
try {
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(is, new DefaultHandler(){
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if(qName == null){
return;
}
if(rootParser != null){
rootParser.startElement(uri, qName, qName, attributes);
}else if(qName.equals(rootParserQName)){
rootParser.parserStart(attributes);
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if(rootParser != null){
rootParser.characters(ch, start, length);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if(qName == null){
return;
}
if(qName.contains(rootParserQName)){
if(rootParser != null){
rootParser.parserEnd();
}
}else if(rootParser != null){
rootParser.endElement(uri, qName, qName);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 节点解析开始
*/
public abstract void parserStart(Attributes attributes);
/**
* 一个子节点解析结束
* @param value characters获得的值
*/
public abstract void parserElementEnd(String qName, String value);
/**
* 解析事件需要向下传递,返回需要传递的子SaxParser
*/
public abstract SaxParser dispatchTo(String qName, Attributes attributes);
/**
* 节点解析结束
*/
public abstract void parserEnd();
}
需要解析的xml文件test.xml:
<?xml version="1.0" encoding="UTF-8"?> <kml xmlns:gx="http://www.google.com/kml/ext/2.2"> <Document id="123"> <description>abc</description> <author>csq</author> <ExtendedData> <Data name="TrackId"> <value>293156</value> </Data> <Data name="TrackTypeId"> <value>8</value> </Data> </ExtendedData> <Placemark> <name>深圳湾公园</name> <TimeStamp> <when>2015-03-21T10:00:13Z</when> </TimeStamp> <Point> <coordinates>113.93946,22.48955,9.0</coordinates> </Point> </Placemark> </Document> </kml>
开始解析:
根节点kml,根节点解析器KmlParser
SaxParser.start(getAssets().open("test.kml"), "kml", new Kml.KmlParser(kml));
部分节点解析实现:
public static class KmlParser extends SaxParser { private Kml kml; public KmlParser(Kml kml) { super(new HashSet<String>()); this.kml = kml; childParserQNames.add("Document"); } @Override public void parserStart(Attributes attributes) { } @Override public void parserElementEnd(String qName, String value) { } @Override public SaxParser dispatchTo(String qName, Attributes attributes) { if(qName.equals("Document")){ return new Document.DocumentParser(kml); } return null; } @Override public void parserEnd() { } }
public static class DocumentParser extends SaxParser { private Kml kml; private Document document; public DocumentParser(Kml kml) { super(new HashSet<String>()); this.kml = kml; childParserQNames.add("ExtendedData"); childParserQNames.add("Placemark"); } @Override public void parserStart(Attributes attributes) { document = new Document(); document.id = attributes.getValue("id"); } @Override public void parserElementEnd(String qName, String value) { if(document == null){ return; } if(qName.equals("description")){ document.description = value; }else if(qName.equals("author")){ document.author = value; } } @Override public SaxParser dispatchTo(String qName, Attributes attributes) { if(document == null){ return null; } if(qName.equals("ExtendedData")){ return new ExtendedData.ExtendedDataParser(document); }else if(qName.equals("Placemark")){ return new Placemark.PlacemarkParser(document); } return null; } @Override public void parserEnd() { kml.document = document; } }
public static class PlacemarkParser extends SaxParser { private Document document; private Placemark placemark; public PlacemarkParser(Document document) { super(new HashSet<String>(1)); childParserQNames.add("Point"); this.document = document; } @Override public void parserStart(Attributes attributes) { placemark = new Placemark(); } @Override public void parserElementEnd(String qName, String value) { if(qName.equals("name")){ placemark.name = value; }else if(qName.equals("when")){ placemark.when = value; } } @Override public SaxParser dispatchTo(String qName, Attributes attributes) { if(qName.equals("Point")){ return new Point.PointParser(placemark); } return null; } @Override public void parserEnd() { document.placemark = placemark; } }
public static class ExtendedDataParser extends SaxParser { private Document document; private ExtendedData extendedData; public ExtendedDataParser(Document document) { super(new HashSet<String>(1)); childParserQNames.add("Data"); this.document = document; } @Override public void parserStart(Attributes attributes) { extendedData = new ExtendedData(); } @Override public void parserElementEnd(String qName, String value) { } @Override public SaxParser dispatchTo(String qName, Attributes attributes) { if(qName.equals("Data")){ return new Data.DataParser(extendedData); } return null; } @Override public void parserEnd() { document.extendedDatas = extendedData; } }
......
解析结果: