初学Android开发乃至Java也初学。
上网搜索了下Android开发中关于XML字符串处理的方法找了个XML对象反射的处理感觉不错,又针对自己常遇到的XML格式进行重新修改调整了下以使得该反射类适用于大部分的XML文件。
具体的处理逻辑是针对XML文件的每个标签在一个package下定义一个同名类,当然如果有一标签是属于集合标签的例如<users><user></user><user></user></users>的则将users及其他类似的节点标签记录在一字符串中并以逗号分隔,在反射类中将对这些标签进行特出处理。
在定义该反射类时需要给其传两个字符串对象:1,所需处理的XML其标签的类定义在的Package的完整名称;2,属于集合标签的以逗号分隔合并的字符串
最后将该处理handler设置给SAX处理。
以下是反射类:
package C6M.ServicesOper;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Stack;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class ReflectResolveXML extends DefaultHandler {
public String PackageNameSpace="";//类名所属空间
public String ClassArray="";//属于数组的节点名称
public String CurTag="";
public String CurTagData="";//String对象值 任何XML标签在数组集合和类集合中不存在的都将被视为String对象
Stack<Object> stack=new Stack<Object>();
private Object root=null;
public Object getRoot() {
return root;
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
//节点结束后都需弹出栈
Object _obj= stack.pop();
//如果属于集合则不进行判断标签名称是在指定命名空间中存在类定义
if(ClassArray.indexOf(","+localName+",")<0)
{
try {
Class localClass= Class.forName(PackageNameSpace+"."+localName);
Object objtest=localClass.getConstructor().newInstance();
} catch (Exception e) {
_obj=CurTagData;
}
}
//获取该节点的父节点
Object _pobj=stack.peek();
//将节点值绑定或者设置到父节点中
injectToParent(_pobj,_obj,localName);
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stu
//可以根据需要修改以下属性代码设置父级对象的属性值
StringBuffer stb=new StringBuffer();
for (int i = 0; i < attributes.getLength(); i++) {
stb.append(attributes.getValue(i)+"---") ;
}
System.out.println("startElement:"+uri+" localName:"+localName+ " qName:"+qName+" Attr: "+stb.toString());
//如果根元素为null 则新建一个 因为第一个读取的必定是根元素
if (root==null) {
root=instanceObjectByType("java.util.ArrayList");
stack.push(root);
}
//如果标签被指定为数组集合则添加数组集合对象到栈中
if(ClassArray.indexOf(","+localName+",")>-1)
{
Object obj=instanceObjectByType("java.util.ArrayList");
stack.push(obj);
return;
}
//String value=attributes.getValue("value");
//String name=attributes.getValue("name");
CurTag=localName;
Object pObj=stack.peek();
Object obj=instanceObjectByType(PackageNameSpace+"."+localName);
stack.push(obj);
//injectToParent(pObj, obj,localName);
}
@Override
public void characters(char[] ch, int start, int length){
// TODO Auto-generated method stub
//super.characters(ch, start, length);
CurTagData= new String(ch, start, length);
}
//转化date类型
private Date typeConvertDate( String value, String pattern) {
SimpleDateFormat sdf=new SimpleDateFormat(pattern);
Date date;
try {
date = sdf.parse(value);
return date;
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
//向上一级元素中注入属性 或者向集合类中add子元素
private void injectToParent(Object pObj, Object fieldValue ,String fieldName) {
if (pObj instanceof Collection) {
//如果上一级是集合类 则需要添加进去
((Collection) pObj).add(fieldValue);
return ;
}
//如果上一级是object 则需要反射字段赋值
Field[] fields = pObj.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.getName().equals(fieldName)) {
try {
field.setAccessible(true);
field.set(pObj, fieldValue);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
}
//反射实例化对象 如果对象类不存在则实例化为string对象
private Object instanceObjectByType(String qName) {
try {
Class localClass= Class.forName(qName);
Object obj=localClass.getConstructor().newInstance();
return obj;
} catch (Exception e) {
// TODO Auto-generated catch block
try
{
Class localClass= Class.forName("java.lang.String");
Object obj=localClass.getConstructor().newInstance();
obj=CurTagData;
return obj;
}catch(Exception e1)
{
e.printStackTrace();
throw new RuntimeException(e1);
}
}
}
// 此方法用于将一个字符串转换为相应的数据类型
public Object typeConvert(String className, String value) {
if (className.equals("java.lang.String")) {
return value;
} else if (className.equals("java.lang.Integer")) {
return Integer.valueOf(value);
} else if (className.equals("java.lang.Long")) {
return Long.valueOf(value);
} else if (className.equals("java.lang.Boolean")) {
return Boolean.valueOf(value);
} else if (className.equals("java.lang.Float")) {
return Float.valueOf(value);
} else if (className.equals("java.lang.Double")) {
return Double.valueOf(value);
} else
return null;
}
}
2:以下是调用示例
public static BackInfo GetLoginInfo(String _xml)
{
BackInfo _ret=new BackInfo();
SAXParser saxParser=null;
XMLReader reader=null;
try {
saxParser=SAXParserFactory.newInstance().newSAXParser();
reader=saxParser.getXMLReader();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FactoryConfigurationError e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ReflectResolveXML reflectResolveXML=new ReflectResolveXML();
reflectResolveXML.PackageNameSpace="C6M.ServicesOper";
reader.setContentHandler(reflectResolveXML);
try {
reader.parse(new InputSource(new StringReader(_xml)));
// List<BackInfo> resources=(List<BackInfo>) reflectResolveXML.getRoot();
_ret=((List<BackInfo>)reflectResolveXML.getRoot()).get(0);
//_ret.ErrorMessage="aaaaaaaaa";
} catch (IOException e) {
// TODO Auto-generated catch block
//_ret.ErrorMessage="BBBBBBBBBBBB";
e.printStackTrace();
} catch (SAXException e) {
//_ret.ErrorMessage="ccccccc";
// TODO Auto-generated catch block
e.printStackTrace();
}
return _ret;
}
3.以下是XML字符串内容
<?xml version="1.0"?> <BackInfo xmlns> <Data>012167</Data> <ErrorMessage /> <Error>0</Error> </BackInfo>
代码2BackInfo是根据XML内容定义的类,但其下属性节点不需要定义成类,反射处理其将会默认把处理处理的认为字符串变量并根据名称赋值给BackInfo的属性
以下是BackInfo的定义
package C6M.ServicesOper;
public class BackInfo {
public String Error="";
public String ErrorMessage="";
public String Data="";
}
事实上经过测试该反射处理目前可以支持多个父子级及多个集合等混合的XML字符串如
<DeptList><Dept><DeptName></DeptName><Users><User>...</User></Users>..</Dept>..</DeptList>