標籤:
dom解析佔用記憶體大(我這邊需要解析各種各樣的kml檔案,有時4-5M的kml檔案使用dom解析很多手機就記憶體溢出了),也需要引入第三方庫,所以使用相對於節省記憶體很多、不需引入其他庫的sax解析就是很好的選擇了。因為sax解析比較複雜的xml檔案特別麻煩,所以整理了一個簡化android sax解析的工具。
實現思路:和Android Touch事件傳遞機制一樣,把需要子解析器解析的節點往下傳遞。
如果有進一步簡化的方法,歡迎交流!email:[email protected]。
樣本程式: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; } }
......
解析結果:
Android簡化xml sax解析