SAX解析xml characters方法要注意的问题

前段时间,在写一段解析xml的代码时发现了一个问题。我用的是SAX,这确实是很简单好用的一个小编。我们只需要继承DefaulHandler ,实现其中的方法即可。但是我们要注意到,其中的 characters 方法在解析一个节点的时候是可能会执行多次的。

假设我们的 persons.xml 文件如下:

<?xml version="1.0" encoding="utf-8"?>
<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,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 qName) throws SAXException {  
        //结束解析节点  
    	super.endElement(uri,qName);
    	flag = false; 
    	if( qName.equals("person")){
    		personList.add(person);
    	}
    }  
}

当然,就解析上面的那段xml ,这是没有问题的。然而让人难堪的是,我想改一下xml ,在某些节点加上 \r \n \t 之类的字符,来证实这样解析会丢失部分数据,却没有成功。它一直工作的很好??? 很多人在博文里说“,当遇到内容中有回车,\t等等内容时,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,attributes);
    	flag = true;
    	if( qName.equals("person")){
    		person = new Person();
    	}
    	node = qName;
    	sb = new StringBuilder();
    }  
      
    public void characters (char[] ch,length);
    	if(!flag) {  
            return;  
        }  
    	sb.append(new String(ch,length) );
    	
    }  
      
    public void endElement (String uri,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;
	   }    	
    }  
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


php输出xml格式字符串
J2ME Mobile 3D入门教程系列文章之一
XML轻松学习手册
XML入门的常见问题(一)
XML入门的常见问题(三)
XML轻松学习手册(2)XML概念
xml文件介绍及使用
xml编程(一)-xml语法
XML文件结构和基本语法
第2章 包装类
XML入门的常见问题(二)
Java对象的强、软、弱和虚引用
JS解析XML文件和XML字符串详解
java中枚举的详细使用介绍
了解Xml格式
XML入门的常见问题(四)
深入SQLite多线程的使用总结详解
PlayFramework完整实现一个APP(一)
XML和YAML的使用方法
XML轻松学习总节篇