標籤:sax xml 多層嵌套
最近工程需要解析多層嵌套XML,沒有找到合適的公用解析的,要是一個類自己對應寫一個解析方法,豈不累死,於是自己寫了個通用的解析類。現在還不是很完善,對子類的解析需要提前指定好子類不能動態解析。
我用的是DefaultHandler來處理XML,裡面方法執行過程是
public void startDocument() throws SAXException
第一個執行方法。
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
該方法是繼第一個方法後第二個執行方法。
public void characters(char[] ch, int start, int length) throws SAXException
這個是繼startElement方法後的執行方法。
該方法中的ch把所解析的xml的所有資料都儲存進來,且ch初始化為2K資料。 start是一個節點">"的位置。length就是">"到下一個"<"的長度。
public void endElement(String uri, String localName, String qName) throws SAXException
若一個節點,比如<name>michael</name>,在執行完characters後會執行該方法。
如果節點,比如<names><name>michael</name></names>在執行names節點時,不會執行到該方法。
public void endDocument() throws SAXException
最後一個執行方法。
解析類如下:
import java.io.IOException;import java.io.StringReader;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.List;import java.util.regex.Matcher;import java.util.regex.Pattern;import javax.xml.parsers.ParserConfigurationException;import javax.xml.parsers.SAXParser;import javax.xml.parsers.SAXParserFactory;import org.xml.sax.Attributes;import org.xml.sax.InputSource;import org.xml.sax.SAXException;import org.xml.sax.XMLReader;import org.xml.sax.helpers.DefaultHandler;import com.app.dftr.tzsb.zf.model.WcfCity;import com.app.dftr.tzsb.zf.model.WcfCounty;import com.app.dftr.tzsb.zf.model.WcfRegion;/** * * 類描述: XML解析類 * * @author CHD * @version * @Date 日期 : 2014-11-7 時間 : 下午3:46:34 */public class SAXParseXMLTools<T> extends DefaultHandler {private String TAG = SAXParseXMLTools.class.getSimpleName();private String content;// 解析內容private String objName;// obj名稱private Object obj;// objprivate Class<?> cla;private ListSets<T> results = null;private Field[] cla_fields;// obj的所有域private Method[] cla_methods;// obj的方法private String tag_name;// 當前標籤private String super_tag_name;// 父級標籤public ListSets<T> getResults() {try {XMLReader reader = null;SAXParserFactory factory = SAXParserFactory.newInstance();reader = factory.newSAXParser().getXMLReader();reader.setContentHandler(this);reader.parse(new InputSource(new StringReader(content)));} catch (Exception e) {// TODO: handle exceptionDebugLog.printError(TAG, "解析出現異常" + e.getMessage());}return results;}public SAXParseXMLTools(String result, Class<?> clas, String objname) {results = new ListSets<T>();content = result;cla = clas;objName = objname;try {obj = cla.newInstance();} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}cla_fields = obj.getClass().getDeclaredFields();// 根據Class對象擷取屬性cla_methods = obj.getClass().getDeclaredMethods();// 根據Class對象擷取所有方法}@Overridepublic void startDocument() throws SAXException {DebugLog.printInfor(TAG, "開始解析!");super.startDocument();}@Overridepublic void endDocument() throws SAXException {DebugLog.printInfor(TAG, "解析完成!");super.endDocument();}@Overridepublic void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {if (qName.equals(objName)) {try {obj = cla.newInstance();} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}super_tag_name = qName;} else {tag_name = qName;try {Field field = obj.getClass().getDeclaredField(tag_name);Class fieldClazz = field.getType(); // 得到field的class及類型全路徑if (fieldClazz.isPrimitive()) { // 【1】 判斷是否為基本類型}if (fieldClazz.getName().startsWith("java.lang")) { // getName()返回field的類型全路徑;}if (fieldClazz.isAssignableFrom(List.class)) // 【2】判斷是否為隊列{Type fc = field.getGenericType(); // 關鍵的地方,如果是List類型,得到其Generic的類型if (null != fc) {if (fc instanceof ParameterizedType) // 【3】如果是泛型參數的類型{ParameterizedType pt = (ParameterizedType) fc;Class genericClazz = (Class) pt.getActualTypeArguments()[0]; // 【4】得到泛型裡的class類型對象。String regex = "<" + tag_name + ">(.*?)</"+ tag_name + ">";Pattern pattern = Pattern.compile(regex);Matcher matcher = pattern.matcher(content);while (matcher.find()) {String tempStr = matcher.group();results.setNextStr(tempStr); // 隊列的字串matcher.replaceFirst("");if(tag_name.equals("City")) {// 城市SAXParseXMLTools<WcfCity> appointHanlder = new SAXParseXMLTools<WcfCity>(tempStr, genericClazz,genericClazz.getSimpleName());ListSets<WcfCity> results = appointHanlder.getResults();try {Class[] args1 = new Class[1];args1[0] = List.class;Method tempMethod = obj.getClass().getDeclaredMethod("set" + tag_name, args1);tempMethod.invoke(obj, results.getResultSet());} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}} else if(tag_name.equals("County")) { // 縣城SAXParseXMLTools<WcfCounty> appointHanlder = new SAXParseXMLTools<WcfCounty>(tempStr, genericClazz,genericClazz.getSimpleName());ListSets<WcfCounty> results = appointHanlder.getResults();try {Class[] args1 = new Class[1];args1[0] = List.class;Method tempMethod = obj.getClass().getDeclaredMethod("set" + tag_name, args1);tempMethod.invoke(obj, results.getResultSet());} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}} else if(tag_name.equals("Region")) { // 地區SAXParseXMLTools<WcfRegion> appointHanlder = new SAXParseXMLTools<WcfRegion>(tempStr, genericClazz,genericClazz.getSimpleName());ListSets<WcfRegion> results = appointHanlder.getResults();try {Class[] args1 = new Class[1];args1[0] = List.class;Method tempMethod = obj.getClass().getDeclaredMethod("set" + tag_name, args1);tempMethod.invoke(obj, results.getResultSet());} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}}} catch (NoSuchFieldException e) {// TODO Auto-generated catch blocke.printStackTrace();}}super.startElement(uri, localName, qName, attributes);}@Overridepublic void endElement(String uri, String localName, String qName)throws SAXException {if (qName.equals(super_tag_name)) {results.getResultSet().add((T) obj);}super.endElement(uri, localName, qName);}@Overridepublic void characters(char[] ch, int start, int length)throws SAXException {String temp = new String(ch, start, length);if (tag_name.equals("_WcfReturnState") && (0 == results.getResult())) {// 解析頭部results.setResult(Integer.parseInt(temp));} else if (tag_name.equals("_WcfReturnMessage")) {results.setMessage(temp);}if (null != super_tag_name && super_tag_name.equals(objName)) {// 確保在父類下 for (Field cla_f : cla_fields) {if (cla_f.getName().equals(tag_name)) {String value = new String(ch, start, length);for (Method cla_method : cla_methods) {String meth = cla_method.getName();// 匹配set方法if (meth != null&& "set".equals(meth.substring(0, 3))&& Modifier.isPublic(cla_method.getModifiers())&& ("set"+ Character.toUpperCase(cla_f.getName().charAt(0)) + cla_f.getName().substring(1)).equals(meth)) {// 調用set方法並賦值try {cla_method.invoke(obj, value);} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}}super.characters(ch, start, length);}}
注釋寫的很詳細。
前端擷取list很簡潔,兩行就ok,
SAXParseXMLTools<WcfEnterprise> appointHanlder = new SAXParseXMLTools<WcfEnterprise>(result, WcfEnterprise.class, WcfEnterprise.class.getSimpleName());ListSets<WcfEnterprise> results = appointHanlder.getResults();
SAX解析多層嵌套XML