在学习的过程中,主要对节点元素、属性、属性值、内容等区别上理解的不够明确,导致第一次使用时,修改了多次。所以以此来总结和记录学习过程
解析xml,主要先通过获取到Document对象,然后根据对象获取到各个节点和节点的属性等。
示例xml内容:
<?xml version="1.0" encoding="UTF-8"?>
<struts>
<action name="login" class="com.coderising.litestruts.LoginAction">
<result name="success">/jsp/homepage.jsp</result>
<result name="fail">/jsp/showLogin.jsp</result>
</action>
<action name="logout" class="com.coderising.litestruts.LogoutAction">
<result name= "success">/jsp/welcome.jsp</result>
<result name= "error">/jsp/error.jsp</result>
</action>
</struts>
一、获取Document 对象
//通过创建SAXReader对象,根据xml文件,传入路径获取Document
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(
new File("src/com/coderising/litestruts/struts.xml"));
二、获取根节点元素对象
Element root = document.getRootElement(); //这里就是struts
//获取所有一级子元素
List<Element> listElement=root.elements(); //两个action
//获取指定元素
Element actionElement = root.element(String str);
//这里都是action,所以可以先获取所有一级子元素后,遍历集合,通过name的属性值来选取所需的action
三、获取元素的属性、属性值及内容
这里以第一个action为例:
1,name和class是属性。相关的API:
List<Attribute> list = element.attributes();//获取所有属性
Attribute attr = element.attribute("name");//获取name属性
attr.getName(); //得到name
2,login和com.coderising.litestruts.LoginAction是属性值
attr.getValue(); //得到“login”
String classStr = element.attribute("class").getValue();
通过类似操作,得到class路径后就可以根据反射来创建对应的class类及对象,然后进行后续的操作。
3,要想获取 /jsp/homepage.jsp 内容,同前面的操作先获取第二级的子元素集合,再根据属性判断,获取想要的result,再根据getText()方法获取内容。
jspStr = resultElement.getText();
流程:这里解析xml的流程是一个简单的登陆流程。外部传入的参数例如是 login的登陆申请,同时传入 帐号密码信息。
通过login这个参数(也就是上面的例子),解析xml,得到第一个action,进而得到对应的class类。根据传入的帐号密码参数,结合反射,对该类进行操作。得到result结果。成功/失败,则进而得到对应的jsp页面。
--------------------------------------------------------------------------------------------------------
再继续记录下反射功能这部分吧。
假设传入的帐号密码是以map的形式:
Map<String,String> params = new HashMap<String,String>();
params.put("name","test");
params.put("password","1234");
并且假设对应的类中,有name,password字段,同时有message字段,
当 name = test,passowrd=1234 (伪代码) 时,返回 “success”
四、通过反射创建对象
Class<?> clazz = Class.forName(classStr); //即LoginAction 类
Object c = clazz.newInstance();
五、运用反射把参数用类的set方法,传入进去。
//获取所有类的字段
Field[] fields = clazz.getDeclaredFields();
可以通过PropertyDescriptor 的getReadMethod()和getWriteMethod()方法获取set/get方法。
通过查看API得知,添加set/get的同时会自动把属性名称的第一个字母改为大写。如果类写的比较规范,那么可以直接使用这两个方法,如果get/set方法名称比较特殊,可以自己写个方法。
//自己写了一个方法,来实现这个转换过程。
public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz,String propertyName) {
StringBuffer sb = new StringBuffer();
Method setMethod = null;
Method getMethod = null;
PropertyDescriptor pd = null;
try {
Field f = clazz.getDeclaredField(propertyName);//根据字段名来获取字段
if (f!= null) {
//构建方法的后缀
String methodEnd = propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
sb.append("set" + methodEnd);
setMethod = clazz.getDeclaredMethod(sb.toString(), new Class[]{f.getType()});
sb.delete(0, sb.length());//清空
sb.append("get" + methodEnd);
//构建get 方法
getMethod = clazz.getDeclaredMethod(sb.toString(), new Class[]{ });
//构建一个属性描述器 把对应属性 propertyName 的 get 和 set 方法保存到属性描述器中
pd = new PropertyDescriptor(propertyName, getMethod, setMethod);
}
} catch (Exception ex) {
ex.printStackTrace();
}
return pd;
}
六、遍历参数,把所有字段都通过set方法写入。
Set<Entry<String, String>> set = map.entrySet();
for(Entry<String, String> entry : set){
String key = entry.getKey();
String val = entry.getValue();
for(Field f :fields){
PropertyDescriptor pd = new PropertyDescriptor(key, clazz);
//这里也可以用自己写的方法
//PropertyDescriptor pd = getPropertyDescriptor(clazz,key);
Method setMethod = pd.getWriteMethod(); //获得用于读取属性值的方法
setMethod.invoke(c, new Object[]{val});
}
}
同理,set后可调用get方法,获取对象的信息进而进行后续操作。
-----------------------------------------------------------------------------------------------
这次学习告一段落,顺便记录下dom4j的几个其他常用api
节点操作:
Element newElement = element.addElement("newNode");
//为newNode节点设置值
newElement.setText("新信息");
属性操作:
Attribute idAttribute = element.attribute("id");
//删除其属性
element.remove(idAttribute);
//为其添加新属性
element.addAttribute("name", "这是element节点的新属性");