Android XML解析(Pull、Sax、Dom)

912 阅读2分钟

1.XmlPullParser

  • 优点:读取方便、内存损耗小

  • 缺点:需要知道节点名称(使用泛型优化)

原理:

基于事件驱动,根据XmlPullParser返回不同的标签进行获取xml数据。

int type = xmlPullParser.getEventType();
while (type!= XmlPullParser.END_DOCUMENT) {
     switch (type) {
         case XmlPullParser.START_DOCUMENT:
             break;
         case XmlPullParser.START_TAG:
             break;
         case XmlPullParser.END_TAG:
             break;
         case XmlPullParser.END_DOCUMENT:
             break;
     }
     type = xmlPullParser.next();
 }

具体例子:

主要是获取到xml的属性赋值给clazz对象, 通过xmlPullParser.nextText()获取value,通过xmlPullParser.getName();获取key进行赋值

public static <T> List<T> xmlToObject(InputStream xml , Class<T> clazz , String tagEntity){
            List<T> list = null;
try{
   XmlPullParser xmlPullParser = Xml.newPullParser();
   xmlPullParser.setInput(xml,"UTF-8");
   Field[] fields = clazz.getDeclaredFields();
   int type = xmlPullParser.getEventType();
   String lastTag = "";
   T t = null;
  	while (type!= XmlPullParser.END_DOCUMENT) {
          switch (type) {
               case XmlPullParser.START_DOCUMENT:
                        String START_DOCUMENTtagName = xmlPullParser.getName();
                        list = new ArrayList<T>();
                        break;
               case XmlPullParser.START_TAG:
                        String tagName = xmlPullParser.getName();
                        if (tagEntity.equals(tagName)) {
                            t = clazz.newInstance();
                            lastTag = tagEntity;
                        } else if (tagEntity.equals(lastTag)) {
                            String value = xmlPullParser.nextText();
                            String filedName = xmlPullParser.getName();
                            for (Field field : fields) {
                               setFieldValue(t, field, filedName, value);
                            }
                        }
                        break;
                 case XmlPullParser.END_TAG:
                        tagName = xmlPullParser.getName();
                        if (tagEntity.equals(tagName)) {
                            list.add(t);
                            lastTag = "";
                        }
                        break;
                  case XmlPullParser.END_DOCUMENT:
                        String tagName1 = xmlPullParser.getName();
                        break;
                }
                type = xmlPullParser.next();
            }
        }catch (Exception e){
                e.printStackTrace();
        }
        return list;
    }
 public static <T> void setFieldValue (T t, Field field , String fieldName ,String  value){
	String name =field.getName();
	if(!fieldName.equals(name)){
	    return;
	}
	//get type
	Type type =field.getType();
	//get modifie
	int typeCode =field.getModifiers();
	String typeName =type.toString();
try{
     switch (typeName){
           case "class java.lang.String":
                        if(Modifier.isPublic(typeCode)){
                            field.set(t,value);
                        }else{
                            Method method =t.getClass().getMethod("set" + getMethodName(fieldName),String.class);
                            method.invoke(t,value);
                        }
                        break;
            case "double":
                        if(Modifier.isPublic(typeCode)){
                            field.set(t,Double.valueOf(value) );
                        }else{
                            Method method =t.getClass().getMethod("set" + getMethodName(fieldName),double.class);
                            method.invoke(t,Double.valueOf(value) );
                        }
                        break;
             case "int":
                        if(Modifier.isPublic(typeCode)){
                            field.set(t,Integer.valueOf(value) );
                        }else{
                            Method method =t.getClass().getMethod("set" + getMethodName(fieldName),int.class);
                            method.invoke(t,Integer.valueOf(value) );
                        }
                        break;
             case "float":
                        if(Modifier.isPublic(typeCode)){
                            field.set(t,Float.valueOf(value) );
                        }else{
                            Method method =t.getClass().getMethod("set" + getMethodName(fieldName),float.class);
                            method.invoke(t,Float.valueOf(value) );
                        }
                        break;

                }
            }catch (Exception e){
                e.printStackTrace();
            }
    }
    
private static String getMethodName(String fieldName) throws Exception{
	byte[] items = fieldName.getBytes();
	items[0] = (byte) ((char)items[0] - 'a' + 'A');
	return new String(items);
}

2.Sax

  • 优点:内存占用少。

  • 缺点:无法修改xml内容,每次都要按顺序读取。

原理:基于事件驱动,扫描文件的开始和结束,继承DefaultHandler类在对应的方法进行处理

例子:

public class SaxHelper<T> extends DefaultHandler {
    String TAG = SaxHelper.class.getSimpleName();
    public   T t;
    private ArrayList<T> tArrayList;
    private String tagName= null;
    Class<T> clazz;
    Field[] fields;
    
   public SaxHelper(Class<T> mClazz){
       clazz=mClazz;
      fields = clazz.getDeclaredFields();
    }
    
    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
        this.tArrayList = new ArrayList<T>();
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        if(localName.equals(clazz.getSimpleName().toLowerCase())){
                try {
                    this.t = clazz.newInstance();
                     fields = clazz.getDeclaredFields();
                    for (Field field : fields) {
                        if(field.getName().equals(Contants.attributeName)){
                            ReflectUtil.setFieldValue(this.t, field, Contants.attributeName, attributes.getValue(Contants.attributeName));
                        }
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        this.tagName = localName;
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
        try {
            if(this.tagName != null) {
                String data = new String(ch,start, length);
                if(data!=null){
                    for (Field field : fields) {
                        if(this.tagName.equals(field.getName())){
                            ReflectUtil.setFieldValue(this.t, field, field.getName(), data);
                        }
                    }
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);
        if(localName.equals(clazz.getSimpleName().toLowerCase())){
            this.tArrayList.add(t);
            t=null;
        }
        this.tagName = null;
    }

    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
        Log.i("SAX", "endDocument");
    }

    //获取persons集合
    public ArrayList<T> getXmlArrayList() {
        return this.tArrayList;
    }
}

3.Dom

  • 优点:检索修改效率高

  • 缺点:损耗内存大,每次都会把xml全部扫描

原理:文档驱动,整个文档树保存在内存中,以便进行操作。

例子:

public class DomHelper {
   static String TAG = DomHelper.class.getSimpleName();
   public static <T>ArrayList<T> queryXML(Context context,Class<T> clazz){
   ArrayList<T> tArrayList = new ArrayList<T>();
        try{
            DocumentBuilderFactory dbFactory=  DocumentBuilderFactory.newInstance();
            DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder();
            Document doc = dbBuilder.parse(context.getAssets().open("person3.xml"));
            NodeList nodeList = doc.getElementsByTagName(clazz.getSimpleName().toLowerCase());
            for(int i = 0;i < nodeList.getLength();i++){
                Element mElement =(Element)nodeList.item(i);
                T t = clazz.newInstance();
                //set attribute
                Field field = clazz.getDeclaredField(Contants.attributeName);
                ReflectUtil.setFieldValue(t, field, Contants.attributeName, mElement.getAttribute(Contants.attributeName));
                //set childNoList
                NodeList childNoList = mElement.getChildNodes();
                for(int j = 0;j<childNoList.getLength();j++){
                    Node childNode = childNoList.item(j);
                    if(childNode.getNodeType() == Node.ELEMENT_NODE){
                        Element childElement = (Element)childNode;
                        Field[] childField = clazz.getDeclaredFields();
                        for (Field mfield:childField){ if(childElement.getNodeName().equals(mfield.getName())){
                                ReflectUtil.setFieldValue(t, mfield, mfield.getName(), childElement.getFirstChild().getNodeValue());
                            }
                        }
                    }
                }
            tArrayList.add(t);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return tArrayList;
    }
}