关于XML文档pull解析的新思考-内省的应用

今天,复习黑马第6天学习的pull解析XML文档,结合第10天讲的JavaBean,突然了有了新的思考。


以下是我创建的XML文档:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 定义一个演示文档,存储黑马的所有班级,以及每个班级的信息
利用XML的功能之一:XML用来表示生活中有关系的数据
 -->
 <itheima>
 	<class>
 		<name>Anroid70期</name>
 		<teacher>于俏</teacher>
 		<time>2015年6月21日</time>
 		<count>77</count>
 	</class>
 	<class>
 		<name>JavaEE70期</name>
 		<teacher>张子艺</teacher>
 		<time>2015年7月2日</time>
 		<count>83</count>
 	</class>
 </itheima>

下面是XML解析的Java代码:

//pull解析xml文档开始。。。。。
		
try {
//第1步:导入pull解析的包,得到pull解析工厂对象
	XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
					
//第2步:通过pull解析工厂得到pull解析器
	XmlPullParser parser = factory.newPullParser();
					
//将XML文档的输入流引入pull解析器
	InputStream in = new FileInputStream("D:\\HeiMa Dairy\\Other\\MyWorkSpace\\JDBCPractice\\WebRoot\\xml\\itheima.xml");
//指定解析器的输入流和编码集
	parser.setInput(in, "utf-8");
//第4步:开始解析
	//创建一个List集合,用来存储javabean,javabean会封装班级信息。
	    List<HeiMaClass> hmClassList = null;
	    HeiMaClass hmClass = null;
	    int type = 0;	//标记解析的位置
	    while((type = parser.getEventType())!= XmlPullParser.END_DOCUMENT)	//到了XML的文档末尾就结束解析
	    {
	//得到标签名,以作相应的判断 。
		String tagName = parser.getName();
						
	//用switch来判断解析的具体位置,比对标签名,采取相应的操作。
		switch(type)
		{
		   case XmlPullParser.START_TAG:	//开始标签
			if("itheima".equals(tagName))
			{
			//创建封装班级javabean的集合对象
			    hmClassList = new ArrayList<HeiMaClass>();
			}
			else if("class".equals(tagName))
			{
			//创建班级javabean,以封装数据
			    hmClass = new HeiMaClass();
			}
			else 
			{	
                                //得到标签内容,用来封装进javabean  hmClass中去。
        			    String tagText = parser.nextText();
        									
        			//利用内省,直接用标签文本,也即Javabean的属性来获取对应
        			//写入方法来赋值。
        			try {
        //内省重要代码************	//构造一个PropertyDescriptor对象
                			  PropertyDescriptor pd = new PropertyDescriptor
                			        (tagName,hmClass.getClass());
        //内省重要代码************      //得到属性的写入方法
                			    Method writeMethod = pd.getWriteMethod();
                			    try {
        //内省重要代码************        	writeMethod.invoke(hmClass, tagText);
                			     } catch (Exception e) {
                				e.printStackTrace();
                			     } 
        			} catch (IntrospectionException e) {
        				e.printStackTrace();
        			}
		          }
			  break;
		    case XmlPullParser.END_TAG:		//结束标签
			if("class".equals(tagName))
			{
			    //将班级对象封装进List集合
			    hmClassList.add(hmClass);
			}
			break;
		    }
		    parser.next();
		}
		//先在控制台上将List集合打印查看一下
		for(HeiMaClass cla : hmClassList)
		{
			System.out.println(cla.toString());
		}
					
		//将List集合写到Session域中,供请求页面获取输出
		request.getSession().setAttribute("hmClassList2", hmClassList);
					
		//转发到请求页面
		request.getRequestDispatcher("/pra/jdbc.jsp").forward(request, response);
	} catch (XmlPullParserException e) {
		e.printStackTrace();
	}

在设计代码的时候,我采用的是javabean封装数据,XML文档中class这个标签对应的javabean代码如下:

//黑马班级类,用来演示pull解析XML,将XML中的班级数据封装到黑马班级类中。
public class HeiMaClass {
	private String name,teacher,time,count;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getTeacher() {
		return teacher;
	}

	public void setTeacher(String teacher) {
		this.teacher = teacher;
	}

	public String getTime() {
		return time;
	}

	public void setTime(String time) {
		this.time = time;
	}

	public String getCount() {
		return count;
	}

	public void setCount(String count) {
		this.count = count;
	}
	
	public String toString()
	{
		return this.name + ":" + this.teacher + ":" + this.time + ":" + this.count;
	}
}

在用else if语句判断对应javabean中的属性标签名时,我发现继续都是用属性名对应的方法来封装数据。那么,有没有可能通过javabean的属性名称(即对应xml文档的标签名称),得到这个属性的set方法呢?

后来我看了一下张孝祥老师的高新技术最后几个视频,发现这个正是内省技术,于是众多的else if语句通过javabean就很轻松的完成了。内省的简单操作是通过java.beans下的PropertyDescriptor类来实现的,构造这个类的对象需传递属性名称和字节码文件,然后通过getWriteMethod即可得到属性对应的写入方法,然后利用反射的原理即可封装数据至javabean中。

-------------------------------------------------------------------------------------------

以前看了反射和内省,当时还是朦朦胧胧,不知道它们到底有什么了不起的。现在我慢慢地发现这些技术如果明白了话,真的是非常实用的,真的像老师所说的,可以让我们少写很多的代码。


同理,pull序列化(将内存中的集合、对象)写到xml文档中去,可以使用反射和内省来减写很多的代码。代码如下:

//从域中得到List集合,hmClassList2。
		List<HeiMaClass> hmClassList = (List<HeiMaClass>)request.getSession().getAttribute("hmClassList2");
		
		//准备进行集合的序列化
		
		try {
			//第1步:得到解析器工厂
			XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
			
			//第2步:从解析器工厂得到序列化的接口
			XmlSerializer serializer = factory.newSerializer();
			
			//第3步:将文件输出流引入到序列化的接口
			OutputStream out = new FileOutputStream("C:\\Users\\LENOVO\\Desktop\\serializer.xml");
			serializer.setOutput(out, "utf-8");
			
			//第4步:正式开始序列化
			//1。生成文档声明和文档结束
			serializer.startDocument(null, true);
			
			//2.生成根标签<itheima>
			serializer.startTag(null, "itheima");
			
			//3.遍历生成字标签
			for(HeiMaClass hmClass : hmClassList)
			{
				//4.生成班级的开始和结束标签
				serializer.startTag(null, "class");
				//利用反射+内省技术,获取HeiMaClass这个javabean的所有属性,并获取它们的值写入xml文档。
				Field[] fields = hmClass.getClass().getDeclaredFields();
				//遍历字段
				for(Field field : fields)
				{
					//获取字段的属性名
					String propertyName = field.getName();
					//得到属性描述器
					try {
						PropertyDescriptor pd = new PropertyDescriptor(propertyName,hmClass.getClass());
						//通过属性描述器得到字段对应的读取方法,获取得它的值并写入XML文档。
						Method readMethod = pd.getReadMethod();
						//调用方法获取属性值 
						try {
							String propertyValue = (String)readMethod.invoke(hmClass);
							//生成开始和结束标签,并插入标签文本。
							serializer.startTag(null, propertyName);
							serializer.text(propertyValue);
							serializer.endTag(null, propertyName);
						} catch (Exception e) {
							e.printStackTrace();
						} 
					} catch (IntrospectionException e) {
						e.printStackTrace();
					}
					
				}
				serializer.endTag(null, "class");
			}
			
			serializer.endTag(null, "itheima");
			
			serializer.endDocument();
			//序列化成功,返回一个提示信息到request域中去
			request.setAttribute("tipXML", "XML文档创建成功,已保存到桌面。");
		} catch (XmlPullParserException e) {
			//序列化失败,返回一个提示信息到request域中去,因为只想失败的一次请求提醒,所以不需要将提示写至session域中去。
			request.setAttribute("tipXML", "XML文档创建失败!");
			e.printStackTrace();
		}finally
		{
			//转发至请求页面
			request.getRequestDispatcher("/pra/jdbc.jsp").forward(request, response);
		}


你可能感兴趣的:(黑马课程)