本工具类:主要运用到了java的反射来解析泛型的属性,并根据泛型属性来设置对象属性值,如果这点弄很熟悉的话,对于类似这种小框架的话应该都不成问题,
我的上一编文章没使用反射与泛型,各位大神可以比较下,哪种方式的灵活度
一.使用dom方式:
package com.example.lxb.mircoxml.xml; import com.example.lxb.mircoxml.AppContext; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; /** * Created by lxb on 2017/4/27. */ public class XmlByDom<T> { /** * T t :为生返回的对象 * <p> * <Volbook> * <p> * <Item> 通常解析从这个结点开始 * <ID>0</ID> * <type>1</type> * <key>518</key> * <cmd>no</cmd> * </Item> * </Volbook> * * @param path * @return */ public List<T> parseXMLByDom(String path, T t) { InputStream is = null; try { is = AppContext.getInstance().getAssets().open(path); Field[] fields = t.getClass().getDeclaredFields(); // 获得实例的属性,顺序并不会保证有序 Map<String, Field> fieldList = FieldUtils.buildFiledList(fields); Method setmeth; // 实例的set方法 List<T> s = new ArrayList<>(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(is); Element rootElement = doc.getDocumentElement(); String secondNode = t.getClass().getSimpleName(); //二级结点作为解析开始的结点 NodeList items = rootElement.getElementsByTagName(secondNode); /** * 每遍历一次解析的结点,需要实例一个对象 */ for (int i = 0; i < items.getLength(); i++) { t = (T) t.getClass().newInstance(); // 获得对象的新的实例 Node item = items.item(i); NodeList properties = item.getChildNodes(); for (int j = 0; j < properties.getLength(); j++) { Node property = properties.item(j); if (property instanceof Element) { String nodeName = property.getNodeName(); /** * 这里主要,处理 反射获取 属性无序的情况 */ String method = "set" + nodeName.substring(0, 1).toUpperCase() + nodeName.substring(1); setmeth = t.getClass().getMethod(method, fieldList.get(nodeName).getType()); //System.out.println("95--------" + fieldList.get(nodeName).getType().toString()); if(fieldList.get(nodeName).getType().toString().equals("int")){ setmeth.invoke(t, Integer.parseInt(property.getFirstChild().getNodeValue())); }else if(fieldList.get(nodeName).getType().toString().equals("boolean")){ setmeth.invoke(t, Boolean.parseBoolean(property.getFirstChild().getNodeValue())); } else{ setmeth.invoke(t, property.getFirstChild().getNodeValue()); } } } s.add(t); } return s; } catch (IOException e) { e.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } }
2.使用SAX方式:
package com.example.lxb.mircoxml.xml; import com.example.lxb.mircoxml.AppContext; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; /** * 使用Sax解析xml文档 * <p> * Created by lxb on 2017/4/26. */ public class ParseXMLSAX<T> { private static ParseXMLSAX parseXMLSAX; public static ParseXMLSAX getInstance() { if (parseXMLSAX == null) { parseXMLSAX = new ParseXMLSAX(); } return parseXMLSAX; } /** * 获取assets文件 * * @param path * @return */ public InputStream getFileInputStream(String path) { try { return AppContext.getInstance().getAssets().open(path); } catch (IOException e) { e.printStackTrace(); } return null; } /** * 解析xml文档 * * @param path * @return * @throws Exception */ public List<T> parse(String path, T t) throws Exception { InputStream is = getFileInputStream(path); SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); SaxXmlHandler<T> handler = new SaxXmlHandler<>(t); parser.parse(is, handler); return handler.getvoiceEntitys(); } /** * DefaultHandler是一个事件处理器,可以接收解析器报告的所有事件,处理所发现的数据 */ private class SaxXmlHandler<T> extends DefaultHandler { private List<T> voiceEntitys; private T second; private StringBuilder builder; private Field[] fields; private String secondNode; private Method setMethod; // 实例的set方法 private Map<String, Field> fieldList; public List<T> getvoiceEntitys() { return voiceEntitys; } public SaxXmlHandler(T t) { this.second = t; } @Override public void startDocument() throws SAXException { // TODO Auto-generated method stub super.startDocument(); voiceEntitys = new ArrayList<>(); builder = new StringBuilder(); fields = this.second.getClass().getDeclaredFields(); // 获得实例的属性,顺序并不会保证有序 fieldList = FieldUtils.buildFiledList(fields); secondNode = this.second.getClass().getSimpleName(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // TODO Auto-generated method stub super.startElement(uri, localName, qName, attributes); if (localName.equals(secondNode)) { //在开始解析的结点处先new一个实例 try { second = (T) this.second.getClass().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } builder.setLength(0); } @Override public void characters(char[] ch, int start, int length) throws SAXException { // TODO Auto-generated method stub super.characters(ch, start, length); builder.append(ch, start, length); //将读取的字符数组追加到builder中 } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // TODO Auto-generated method stub super.endElement(uri, localName, qName); try { if(fieldList.containsKey(localName)){ String method = "set" + localName.substring(0, 1).toUpperCase() + localName.substring(1); setMethod = this.second.getClass().getMethod(method, fieldList.get(localName).getType()); if(fieldList.get(localName).getType().toString().equals("int")){ setMethod.invoke(this.second, Integer.parseInt(builder.toString())); }else if(fieldList.get(localName).getType().toString().equals("boolean")){ setMethod.invoke(this.second, Boolean.parseBoolean(builder.toString())); } else{ setMethod.invoke(this.second, builder.toString()); } } if(localName.equals(secondNode)){ //说明第一层结点解析结束 voiceEntitys.add(this.second); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } }
3.工具类:
package com.example.lxb.mircoxml.xml; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; /** * Created by lxb on 2017/4/28. */ public class FieldUtils { public static Map<String, Field> buildFiledList(Field[] fields) { Map<String, Field> fieldList = new HashMap<>(); for (int i = 0; i < fields.length; i++) { String key = fields[i].toString().substring(fields[i].toString().lastIndexOf(".") + 1, fields[i].toString().length()); fieldList.put(key, fields[i]); } return fieldList; } }
4.与xml文件对应的实体类:
package com.example.lxb.mircoxml.model; /** * Created by lxb on 2017/4/27. */ public class Item { private int ID; private String type; private String key; private String cmd; private boolean b; public int getID() { return ID; } public void setID(int ID) { this.ID = ID; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getCmd() { return cmd; } public void setCmd(String cmd) { this.cmd = cmd; } public void setB(boolean b){ this.b = b; } public boolean getB(){ return this.b; } }
xml文件:
<?xml version="1.0" encoding="UTF-8"?> <volbook> <!-- 音量加 --> <Item> <ID>0</ID> <type>1</type> <key>518</key> <cmd>ywrtwer</cmd> <b>true</b> </Item> <!-- 音量减 --> <Item> <ID>1</ID> <type>1</type> <key>517</key> <cmd>no</cmd> <b>true</b> </Item> <!-- 亮度加 --> <Item> <ID>2</ID> <type>1</type> <key>520</key> <cmd>刘胡来</cmd> <b>true</b> </Item> </volbook>
6.测试代码:
private void readDom(){ /* XmlByDom<Item> dom = new XmlByDom<>(); List<Item> tt = dom.parseXMLByDom("123.xml",new Item());*/ ParseXMLSAX<Item> dom = new ParseXMLSAX<>(); List<Item> tt = null; try { tt = dom.parse("123.xml",new Item()); } catch (Exception e) { e.printStackTrace(); } System.out.println("62------------------id :"+tt.get(0).getID() + " type:" + tt.get(0).getType() + " key:" + tt.get(0).getKey() + " cmd:" +tt.get(0).getCmd() + " b: "+tt.get(0).getB()); }
可以仿造这种方式将任意对象写到xml文件中去