SAX解析characters 错误截取问题的解决

SAX的工作原理简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知 事件处理函数 ,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。

 

<?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中即可。像下面的这种写法是可能会有问题的:

/**   
  1.  * @Title: MySaxHandler.java 
  2.  * @Description: TODO 
  3.  * @author ThinkPad 
  4.  * @version 1.0 
  5.  * @date 2014年7月13日 
  6.  */  
  7. package com.sax.example;  
  8.   
  9. import java.util.ArrayList;  
  10. import java.util.List;  
  11.   
  12. import org.xml.sax.Attributes;  
  13. import org.xml.sax.SAXException;  
  14. import org.xml.sax.helpers.DefaultHandler;  
  15.   
  16. /** 
  17.  * @author ThinkPad 
  18.  * 
  19.  */  
  20. public class MySaxHandler1 extends DefaultHandler {  
  21.   
  22.     /** 
  23.      *  xml 解析结果 
  24.      */  
  25.     public static List<Person> personList;  
  26.       
  27.     private Person person;  
  28.       
  29.     private String node;  
  30.       
  31.     private boolean flag = false;   
  32.       
  33.     public void startDocument () throws SAXException {    
  34.         //开始解析文档     
  35.         super.startDocument();  
  36.         personList = new ArrayList<Person>();  
  37.     }    
  38.     
  39.     public void endDocument () throws SAXException {    
  40.         //文档解析结束     
  41.         super.endDocument();  
  42.     }    
  43.     
  44.     public void startElement (String uri, String localName, String qName, Attributes attributes) throws SAXException {    
  45.         //开始解析节点     
  46.         super.startElement(uri, localName, qName, attributes);  
  47.         flag = true;   
  48.         if( qName.equals("person")){  
  49.             person = new Person();  
  50.         }  
  51.         node = qName;  
  52.     }    
  53.         
  54.     public void characters (char[] ch, int start, int length) throws SAXException {    
  55.         //保存节点内容     
  56.         super.characters(ch, start, length);  
  57.           
  58.         if(!flag) {    
  59.             return;    
  60.         }    
  61.           
  62.         String s = new String(ch, start, length);     
  63.         switch (node) {  
  64.             case "name":  
  65.                   person.setName(s);  
  66.                  break;  
  67.             case "sex":  
  68.                  person.setSex(s);  
  69.                  break;    
  70.             case "age":  
  71.                  person.setAge(s);  
  72.                  break;  
  73.             default:  
  74.                 break;  
  75.         }     
  76.     }    
  77.         
  78.     public void endElement (String uri, String localName, String qName) throws SAXException {    
  79.         //结束解析节点     
  80.         super.endElement(uri, localName, qName);  
  81.         flag = false;   
  82.         if( qName.equals("person")){  
  83.             personList.add(person);  
  84.         }  
  85.     }    
  86. }  
/**  
 * @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 ,在某些节点加上 \r \n \t 之类的字符,来证实这样解析会丢失部分数据,却没有成功。它一直工作的很好??? 很多人在博文里说“,当遇到内容中有回车,\t等等内容时,characters 方法有可能会执行多次”,看来在这种情况下也未必一定会执行多次。这是随机的? 总之,我在生产环境中,使用类似上面的解析方法确实遇到了截断节点数据的问题。因此,我确信,上面的写法是有问题的。

正确的、合理的写法如下,用一个StringBuilder 在characters 方法中拼接数据,在 endElement 方法中填充数据。

  1. /**   
  2.  * @Title: MySaxHandler.java 
  3.  * @Description: TODO 
  4.  * @author ThinkPad 
  5.  * @version 1.0 
  6.  * @date 2014年7月13日 
  7.  */  
  8. package com.sax.example;  
  9.   
  10. import java.util.ArrayList;  
  11. import java.util.List;  
  12.   
  13. import org.xml.sax.Attributes;  
  14. import org.xml.sax.SAXException;  
  15. import org.xml.sax.helpers.DefaultHandler;  
  16.   
  17. /** 
  18.  * @author ThinkPad 
  19.  * 
  20.  */  
  21. public class MySaxHandler extends DefaultHandler {  
  22.   
  23.     /** 
  24.      *  xml 解析结果 
  25.      */  
  26.     public static List<Person> personList;  
  27.       
  28.     private Person person;  
  29.       
  30.     private String node;  
  31.       
  32.     private StringBuilder sb;  
  33.       
  34.     private boolean flag = false;  
  35.       
  36.     public void startDocument () throws SAXException {    
  37.         //开始解析文档     
  38.         super.startDocument();  
  39.         personList = new ArrayList<Person>();  
  40.     }    
  41.     
  42.     public void endDocument () throws SAXException {    
  43.         //文档解析结束     
  44.         super.endDocument();  
  45.     }    
  46.     
  47.     public void startElement (String uri, String localName, String qName, Attributes attributes) throws SAXException {    
  48.         //开始解析节点     
  49.         super.startElement(uri, localName, qName, attributes);  
  50.         flag = true;  
  51.         if( qName.equals("person")){  
  52.             person = new Person();  
  53.         }  
  54.         node = qName;  
  55.         sb = new StringBuilder();  
  56.     }    
  57.         
  58.     public void characters (char[] ch, int start, int length) throws SAXException {    
  59.         //保存节点内容     
  60.         super.characters(ch, start, length);  
  61.         if(!flag) {    
  62.             return;    
  63.         }    
  64.         sb.append(new String(ch, start, length) );  
  65.           
  66.     }    
  67.         
  68.     public void endElement (String uri, String localName, String qName) throws SAXException {    
  69.         //结束解析节点     
  70.         super.endElement(uri, localName, qName);  
  71.         flag = false;   
  72.         if( qName.equals("person")){  
  73.             personList.add(person);  
  74.         }  
  75.         String s = sb.toString();  
  76.         switch (node) {  
  77.             case "name":  
  78.                   person.setName(s);  
  79.                  break;  
  80.             case "sex":  
  81.                  person.setSex(s);  
  82.                  break;    
  83.             case "age":  
  84.                  person.setAge(s);  
  85.                  break;  
  86.             default:  
  87.                 break;  
  88.        }          
  89.     }    
  90. }  

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值