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

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


以下是我创建的XML文档:

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

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

//黑马班级类,用来演示pull解析XML,将XML中的班级数据封装到黑马班级类中。
publicclassHeiMaClass{
	privateStringname,teacher,time,count;

	publicStringgetName(){
		returnname;
	}

	publicvoidsetName(Stringname){
		this.name=name;
	}

	publicStringgetTeacher(){
		returnteacher;
	}

	publicvoidsetTeacher(Stringteacher){
		this.teacher=teacher;
	}

	publicStringgetTime(){
		returntime;
	}

	publicvoidsetTime(Stringtime){
		this.time=time;
	}

	publicStringgetCount(){
		returncount;
	}

	publicvoidsetCount(Stringcount){
		this.count=count;
	}
	
	publicStringtoString()
	{
		returnthis.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步:得到解析器工厂
			XmlPullParserFactoryfactory=XmlPullParserFactory.newInstance();
			
			//第2步:从解析器工厂得到序列化的接口
			XmlSerializerserializer=factory.newSerializer();
			
			//第3步:将文件输出流引入到序列化的接口
			OutputStreamout=newFileOutputStream("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(HeiMaClasshmClass:hmClassList)
			{
				//4.生成班级的开始和结束标签
				serializer.startTag(null,"class");
				//利用反射+内省技术,获取HeiMaClass这个javabean的所有属性,并获取它们的值写入xml文档。
				Field[]fields=hmClass.getClass().getDeclaredFields();
				//遍历字段
				for(Fieldfield:fields)
				{
					//获取字段属性名
					StringpropertyName=field.getName();
					//得到属性描述器
					try{
						PropertyDescriptorpd=newPropertyDescriptor(propertyName,hmClass.getClass());
						//通过属性描述器得到字段对应的读取方法获取得它的值并写入XML文档。
						MethodreadMethod=pd.getReadMethod();
						//调用方法获取属性值
						try{
							StringpropertyValue=(String)readMethod.invoke(hmClass);
							//生成开始和结束标签,并插入标签文本。
							serializer.startTag(null,propertyName);
							serializer.text(propertyValue);
							serializer.endTag(null,propertyName);
						}catch(Exceptione){
							e.printstacktrace();
						}
					}catch(IntrospectionExceptione){
						e.printstacktrace();
					}
					
				}
				serializer.endTag(null,"class");
			}
			
			serializer.endTag(null,"itheima");
			
			serializer.endDocument();
			//序列化成功,返回一个提示信息到request域中去
			request.setAttribute("tipXML","XML文档创建成功,已保存到桌面。");
		}catch(XmlPullParserExceptione){
			//序列化失败,返回一个提示信息到request域中去,因为只想失败的一次请求提醒,所以不需要将提示写至session域中去。
			request.setAttribute("tipXML","XML文档创建失败!");
			e.printstacktrace();
		}finally
		{
			//转发至请求页面
			request.getRequestdispatcher("/pra/jdbc.jsp").forward(request,response);
		}


内省在WEB中的一个小小的应用,

比如在Servlet里获取请求参数,可以利用内省根据属性获取属性方法,将属性赋值给JavaBean.

相关文章

php输出xml格式字符串
J2ME Mobile 3D入门教程系列文章之一
XML轻松学习手册
XML入门的常见问题(一)
XML入门的常见问题(三)
XML轻松学习手册(2)XML概念