SAX解析和生成XML文档
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本人声明。否则将追究法律责任。
作者:永恒の_☆ 地址:http://blog.csdn.net/chenghui0317/article/details/11990891一、前言
SAX操作xml是基于事件来完成的,自己只负责调用解析的方法,然后具体解析操作都是交给DefaultHandler处理者来完成的,总的来说使用SAX解析和生成xml文档还是比较方便的 。
因为SAX是jdk自带的解析方式,所以不用添加jar包引用。
实现思路:
<1>先由SAXParserFactory这个工厂的实例生产一个SAXParser解析器;
<2>然后根据读取的xml路径,传递给SAXParser这个解析器,再调用parse()方法;
<3>在parse()方法中需要传递DefaultHandler这个类的扩展类的实例,因为它才会真正去一步步去解析xml文档的;
<4>在DefaultHandler扩展类中需要重写startDocument(),endDocument()等等方法,因为他们方法内部有返回的具体文档的结果。
具体代码如下:
根据控制台的显示可知:
<1>解析类必须继承DefaultHandler这个类,重写自己需要获取节点信息的方法,不重写的情况下会调用父类的对应方法,所以不影响程序;
<2>XmlSAXHandler01这个处理者来完成xml的解析工作,并且调用方式是按照xml层级关系来处理的,比如最开始调用startDocument()获取Document对象,然后再递归调用startElement()获取根节点以及子节点的信息,其中的characters()用于获取节点文本内容信息,待节点解析完毕之后会调用endElement(),同样整个xml解析完毕之后会调用endDocument()结束。
上面只是简单的获取了xml的根目录的元素,接下来使用DefaultHandler这个处理者怎么获取节点内的信息。
具体代码如下:
根据控制台的显示可知:
<1>XMLSAXHandler02在解析的时候执行方法是从最外层往内、从上往下依次解析的,并且每一次解析节点都是startElement()和endElement()成对出现的;
<2>图中显示了每一个节点解析的信息,并且startElement()和endElement()的区别在于前面方法有携带属性,而后面方法没有;
<3>图中之所以出现三个“节点元素文本内容”是XMLSAXHandler02也是把非标签的文本当前一个节点了,所以在解析的时候要排除这种情况,以免影响最终想要的结果。
另外发现:
<1>查看父类的方法发现它们的方法体什么都没做;
<2>SAX不支持重新修改XML的结构;
<3>如果正常业务需求,解析xml之后不可能只是简单输出下内容,而是要返回成一个集合或者其他形式返回,目前情况可以使用全局的ArrayList集合来完成解析之后节点内容的封装。
接下来需要实现如何封装SAX解析完毕的XML文档,都知道java是面向对象编程的,那么这个时候可以把文档中的每一个节点都看成一个对象,包括节点里面的属性也是一样,那么在解析XML的时候直接使用javabean封装一下,思路就非常清晰了,但是现在还有还一个问题: 如何在SAXParser调用parse()方法之后返回最终的结果集呢?就目前肯定不行的,其一方法没有返回值,其二解析操作完全交给DefaultHandler去做了,所以这种情况下肯定不能使用普通变量或者全局变量,因为使用了之后会随着当前操作类的实例化生命周期而存在,并且DefaultHandler在调用的时候又需要产生一个新的实例,这样前后就没有关联性了。 所以只能使用静态ArrayList来完成了。
具体操作如下:
1、前面说了构建节点对象和属性对象,具体代码如下:
根据控制台的显示可知:
<1>使用全局静态变量完成完成了对Xml解析之后的封装工作,并且在输出的时候没有问题,但是需要注意的是去掉空文本节点这种特殊情况,否则会出现获取的节点内的内容为"\n\t" 等等结果;<2>虽然功能是完成了,但是如果Xml文档中录入的不是文本,而是添加的详细的子节点呢?这样每一个节点就是一个Node对象,在查询和使用的时候非常的不方便。
所以为了避免这种情况,作出如下改动:
因为需求只需要获取User信息,那么不用每一个解析的节点都封装成一个对象,并且属性对象和节点对象可以合并,不用分太开这样不易于后期维护。
具体操作如下:
假设现在需要解析的xml文档如下:
好了,现在满足需求了 解析自己需要的节点然后封装成集合展示出来。
2、生成xml文档
SAX能够解析xml,同样肯定能生成xml,而且使用起来也不是很复杂。
实现思路:
<1>创建保存xml的结果流对象StreamResult;
<2>然后利用SAXTransformerFactory这个工厂创建TransformerHandler这个操作者;
<3>操作这个TransformerHandler获取Transformer,利用Transformer创建节点信息;
具体代码如下:然后看看生成的XML,结构如下:
结果显示达到了期望,但是有一个问题:
如果使用transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8"); 重新指定了编码,插入的中文会变成乱码,现在没有想到解决方案。。
但是如果不指定编码 却没有问题,显示结果是上图中的默认的UTF-8。