java实战之解析xml
在java中解析xml有现成的包提供方法,常用的有四类:Dom,JDom,Sax以及Dom4j。其中前者是java中自带的,后三者需要大家从开源诸如sourceforge这样的网站下载jar包,然后在eclipse中“build path”加载外来的jar文件就行。各自的入门demo可以观看官网文档,听说文档有点晦涩难懂,可以多多google之,园子里有的是资源。接下来主要讲的是如何使用Dom4j解析xml文档。
1、什么是xml
首先从维基百科里盗图一张,解释xml的主要结构——『节点(node):节点名称和节点值。』,『属性(attribute):属性名称和属性值。』。
上图中第一行解释了该xml文件的版本信息,这在写入xml文件的时候需要注明,有时候还需要注明文件的编码方式例如“utf-8”。在每一个xml文件中都有一个根节点,所有节点数据都是包含在根节点中,例如本xml文档中的根节点名称为quiz。quiz根节点下有一个名称为qanda子节点,这样类似的子节点是可重复的,当然在本xml文件中根节点下只有一个直系子节点qanda,qanda节点中有一个名称为seq的属性,其属性值为“1”,在qanda中有两个子节点,第一个子节点为question,该子节点的节点值为Who was the forty-second....一堆文字,符号标签</question>标志着该节点值的结束。以此类推第二个子节点answer的节点值(节点内容)为William....,后面<!--....>里面的内容是注释,类似html文件中的注释信息。
对xml语言有更多兴趣的可去w2school网站文档学习。
2、开始实战
2.1 准备材料
以下是我的xml文档示例,目的是了解xml文档的结构(完整文档见“下载我吧~”):
上面的截图中,第一个文件ccms_position.xml文件就是传说中的标记语言,常用语web service中数据的传输,在eclipse中xml文件有两种展示方式(以上展示的是Source源文件模式),它为了让程序员方便的解析和编写xml文件特意设计的Design模式真的很人性化(自行在eclipse中打开xml文件就可以切换Design模式)。
2.2 测试结果分析
上面的XmlDemo和XmlTest分别是demo和测试文件,所有代码如下:
1 package com.xml;
2
3 import java.io.File;
4 import java.io.FileWriter;
5 import java.io.IOException;
6 import java.util.Iterator;
7
8 import org.dom4j.Document;
9 import org.dom4j.DocumentException;
10 import org.dom4j.Element;
11 import org.dom4j.io.SAXReader;
12
13 /**
14 * @author 吴荧
15 *
16 * 解析XML文档
17 */
18
19 public class XmlDemo{
20
21 public void parseXml(String inputName, String outputName) {
22
23 File inputXml = new File(inputName);
24 SAXReader saxReader = new SAXReader();
25
26 try {
27 //新建输出文件
28 FileWriter writer = new FileWriter(outputName);
29 //读取XML文件,获取document对象
30 Document document = saxReader.read(inputXml);
31 //获取根节点msgData元素对象
32 Element msgData = document.getRootElement();
33
34 //获取根节点下的子节点strPhoneNO以及该节点名称的内容并写入文件
35 Element strPhoneNO = msgData.element("strPhoneNO");
36 String strPhoneNO_text = strPhoneNO.getTextTrim();
37 writer.write(strPhoneNO_text + ",");
38
39 //获取根节点下的子节点PositionData
40 Element PositionData = msgData.element("PositionData");
41 String PositionData_text = PositionData.getTextTrim();
42 writer.write(PositionData_text + ",");
43
44 //在PositionData中迭代第一层子节点
45 for (Iterator i = PositionData.elementIterator(); i.hasNext();){
46
47 Element node1 = (Element) i.next();
48 //将第一层子节点中的文字写入文本
49 writer.write(node1.getTextTrim());
50 if (i.hasNext()){
51 writer.write(",");
52 }
53
54 //第一层子节点中再次遍历第二层子节点
55 for (Iterator j = node1.elementIterator(); j.hasNext();){
56
57 Element node2 = (Element) j.next();
58 //将第二层子节点中的文字写入文本
59 writer.write(node2.getTextTrim());
60 if (j.hasNext()){
61 writer.write(",");
62 }
63
64 //第二层子节点中再次遍历第三层子节点
65 for (Iterator k = node2.elementIterator(); k.hasNext();){
66
67 Element node3 = (Element) k.next();
68 //将第三层子节点中的文字写入文本
69 writer.write(node3.getTextTrim());
70 if (k.hasNext()){
71 writer.write(",");
72 }
73 }
74 }
75 } writer.close();
76 } catch (DocumentException e) {
77 System.out.println(e.getMessage());
78 } catch (IOException e) {
79 e.printStackTrace();
80 }
81 }
82 }
1 package com.xml;
2
3 /*
4 * 测试代码
5 */
6
7 public class XmlTest {
8
9 public static void main(String [] args) {
10 String inputName = "src/com/xml/ccms_position.xml";
11 String outputName = "src/com/xml/ccms_out.txt";
12
13 XmlDemo demo4 = new XmlDemo();
14 demo4.parseXml(inputName, outputName);
15 }
16 }
上面的代码注释已经是非常详细了,其中的语法主要参考的是这篇博文,但是写入的结果并不如人意,如下图所示:
写入文件的目的:希望解析xml文档中的所有数据,并将数据按不同字段用逗号分割符分开存入文本。
目前代码存在的问题:
2.2.1 每遍历一个层结束以后,使用i.hasNext()方法判断是都还有下一个节点的时候被写入一个逗号,但是遇到下一个节点中是子节点而没有节点内容的时候不应该写入数据,否则就会出现第二行输出的两个逗号之间没有数据;
2.2.2 看样本中nSec节点中的内容0与nApdMsg节点中的内容8没有使用逗号分隔符分隔,考虑到也是使用i.hasNext方法的问题,应该考虑该节点的母节点遍历结束以后都要使用逗号分隔。
2.3 调试代码
更改逗号写入条件:当前同一层节点的内容用逗号分隔;当该层循环结束,若下层节点中无文本内容只有子节点的时候不写入逗号,仅当节点有文本内容的时候才将内容写入文本并使用逗号分隔。
在每一层循环中写入以下判断条件再写入:
1 if (!nodei.getTextTrim().equals("")){
2 writer.write(nodei.getTextTrim());
3 if (i.hasNext()){
4 writer.write(",");
5 }
6 }
解决了了2.2.1的问题,但是2.2.2的问题仍然没有解决,只能手动在第一层写入数据之前加入逗号,感觉代码好low啊。
2.4 优化代码
2.4.1 代码中存在大量的重复块,可以将重复块写入方法调用
1 public Element condition(FileWriter writer, Iterator m) throws IOException {
2
3 Element node = (Element) m.next();
4 //将第一层子节点中的文字写入文本
5 String text = node.getTextTrim();
6 if (!text.equals("")){
7 writer.write(node.getTextTrim());
8 if (m.hasNext()){
9 writer.write(",");
10 }
11 }
12 return node;
13 }
2.5 看看其他的算法
2.5.1 Dom
2.5.2 Sax
2.5.3 JDom
挖个坑,先把jar包的资源扔出来~