SAX解析xml characters方法要注意的问题
https://blog.csdn.net/zhutulang/article/details/37736407
前段时间,在写一段解析xml的代码时发现了一个问题。我用的是SAX,这确实是很简单好用的一个东东。我们只需要继承DefaulHandler ,实现其中的方法即可。但是我们要注意到,其中的 characters 方法在解析一个节点的时候是可能会执行多次的。
假设我们的 persons.xml 文件如下:
-
-
<persons>
-
<person>
-
<name>Tom Jeff</name>
-
<sex>M</sex>
-
<age>20</age>
-
</person>
-
<person>
-
<name>Cater</name>
-
<sex>M</sex>
-
<age>23</age>
-
</person>
-
<person>
-
<name>Susan</name>
-
<sex>F</sex>
-
<age>19</age>
-
</person>
-
<person>
-
<name>Lily</name>
-
<sex>F</sex>
-
<age>22</age>
-
</person>
-
</persons>
这段xml 很简单,我们要做的事情也很简单,只需要把其中的person 解析出来放入一个list中即可。像下面的这种写法是可能会有问题的:
-
/**
-
* @Title: MySaxHandler.java
-
* @Description: TODO
-
* @author ThinkPad
-
* @version 1.0
-
* @date 2014年7月13日
-
*/
-
package com.sax.example;
-
-
import java.util.ArrayList;
-
import java.util.List;
-
-
import org.xml.sax.Attributes;
-
import org.xml.sax.SAXException;
-
import org.xml.sax.helpers.DefaultHandler;
-
-
/**
-
* @author ThinkPad
-
*
-
*/
-
public class MySaxHandler1 extends DefaultHandler {
-
-
/**
-
* xml 解析结果
-
*/
-
public static List<Person> personList;
-
-
private Person person;
-
-
private String node;
-
-
private boolean flag = false;
-
-
public void startDocument () throws SAXException {
-
//开始解析文档
-
super.startDocument();
-
personList = new ArrayList<Person>();
-
}
-
-
public void endDocument () throws SAXException {
-
//文档解析结束
-
super.endDocument();
-
}
-
-
public void startElement (String uri, String localName, String qName, Attributes attributes) throws SAXException {
-
//开始解析节点
-
super.startElement(uri, localName, qName, attributes);
-
flag = true;
-
if( qName.equals("person")){
-
person = new Person();
-
}
-
node = qName;
-
}
-
-
public void characters (char[] ch, int start, int length) throws SAXException {
-
//保存节点内容
-
super.characters(ch, start, length);
-
-
if(!flag) {
-
return;
-
}
-
-
String s = new String(ch, start, length);
-
switch (node) {
-
case "name":
-
person.setName(s);
-
break;
-
case "sex":
-
person.setSex(s);
-
break;
-
case "age":
-
person.setAge(s);
-
break;
-
default:
-
break;
-
}
-
}
-
-
public void endElement (String uri, String localName, String qName) throws SAXException {
-
//结束解析节点
-
super.endElement(uri, localName, qName);
-
flag = false;
-
if( qName.equals("person")){
-
personList.add(person);
-
}
-
}
-
}
当然,就解析上面的那段xml ,这是没有问题的。然而让人难堪的是,我想改一下xml ,在某些节点加上 之类的字符,来证实这样解析会丢失部分数据,却没有成功。它一直工作的很好??? 很多人在博文里说“,当遇到内容中有回车, 等等内容时,characters 方法有可能会执行多次”,看来在这种情况下也未必一定会执行多次。这是随机的? 总之,我在生产环境中,使用类似上面的解析方法确实遇到了截断节点数据的问题。因此,我确信,上面的写法是有问题的。
正确的、合理的写法如下,用一个StringBuilder 在characters 方法中拼接数据,在 endElement 方法中填充数据。
-
/**
-
* @Title: MySaxHandler.java
-
* @Description: TODO
-
* @author ThinkPad
-
* @version 1.0
-
* @date 2014年7月13日
-
*/
-
package com.sax.example;
-
-
import java.util.ArrayList;
-
import java.util.List;
-
-
import org.xml.sax.Attributes;
-
import org.xml.sax.SAXException;
-
import org.xml.sax.helpers.DefaultHandler;
-
-
/**
-
* @author ThinkPad
-
*
-
*/
-
public class MySaxHandler extends DefaultHandler {
-
-
/**
-
* xml 解析结果
-
*/
-
public static List<Person> personList;
-
-
private Person person;
-
-
private String node;
-
-
private StringBuilder sb;
-
-
private boolean flag = false;
-
-
public void startDocument () throws SAXException {
-
//开始解析文档
-
super.startDocument();
-
personList = new ArrayList<Person>();
-
}
-
-
public void endDocument () throws SAXException {
-
//文档解析结束
-
super.endDocument();
-
}
-
-
public void startElement (String uri, String localName, String qName, Attributes attributes) throws SAXException {
-
//开始解析节点
-
super.startElement(uri, localName, qName, attributes);
-
flag = true;
-
if( qName.equals("person")){
-
person = new Person();
-
}
-
node = qName;
-
sb = new StringBuilder();
-
}
-
-
public void characters (char[] ch, int start, int length) throws SAXException {
-
//保存节点内容
-
super.characters(ch, start, length);
-
if(!flag) {
-
return;
-
}
-
sb.append(new String(ch, start, length) );
-
-
}
-
-
public void endElement (String uri, String localName, String qName) throws SAXException {
-
//结束解析节点
-
super.endElement(uri, localName, qName);
-
flag = false;
-
if( qName.equals("person")){
-
personList.add(person);
-
}
-
String s = sb.toString();
-
switch (node) {
-
case "name":
-
person.setName(s);
-
break;
-
case "sex":
-
person.setSex(s);
-
break;
-
case "age":
-
person.setAge(s);
-
break;
-
default:
-
break;
-
}
-
}
-
}