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

前端之家收集整理的这篇文章主要介绍了SAX解析xml characters方法要注意的问题前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

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

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

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <persons>
  3. <person>
  4. <name>Tom Jeff</name>
  5. <sex>M</sex>
  6. <age>20</age>
  7. </person>
  8. <person>
  9. <name>Cater</name>
  10. <sex>M</sex>
  11. <age>23</age>
  12. </person>
  13. <person>
  14. <name>Susan</name>
  15. <sex>F</sex>
  16. <age>19</age>
  17. </person>
  18. <person>
  19. <name>Lily</name>
  20. <sex>F</sex>
  21. <age>22</age>
  22. </person>
  23. </persons>

这段xml 很简单,我们要做的事情也很简单,只需要把其中的person 解析出来放入一个list中即可。像下面的这种写法是可能会有问题的:
  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 MySaxHandler1 extends DefaultHandler {
  22.  
  23. /**
  24. * xml 解析结果
  25. */
  26. public static List<Person> personList;
  27. private Person person;
  28. private String node;
  29. private boolean flag = false;
  30. public void startDocument () throws SAXException {
  31. //开始解析文档
  32. super.startDocument();
  33. personList = new ArrayList<Person>();
  34. }
  35. public void endDocument () throws SAXException {
  36. //文档解析结束
  37. super.endDocument();
  38. }
  39. public void startElement (String uri,String localName,String qName,Attributes attributes) throws SAXException {
  40. //开始解析节点
  41. super.startElement(uri,localName,qName,attributes);
  42. flag = true;
  43. if( qName.equals("person")){
  44. person = new Person();
  45. }
  46. node = qName;
  47. }
  48. public void characters (char[] ch,int start,int length) throws SAXException {
  49. //保存节点内容
  50. super.characters(ch,start,length);
  51. if(!flag) {
  52. return;
  53. }
  54. String s = new String(ch,length);
  55. switch (node) {
  56. case "name":
  57. person.setName(s);
  58. break;
  59. case "sex":
  60. person.setSex(s);
  61. break;
  62. case "age":
  63. person.setAge(s);
  64. break;
  65. default:
  66. break;
  67. }
  68. }
  69. public void endElement (String uri,String qName) throws SAXException {
  70. //结束解析节点
  71. super.endElement(uri,qName);
  72. flag = false;
  73. if( qName.equals("person")){
  74. personList.add(person);
  75. }
  76. }
  77. }

当然,就解析上面的那段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. private Person person;
  28. private String node;
  29. private StringBuilder sb;
  30. private boolean flag = false;
  31. public void startDocument () throws SAXException {
  32. //开始解析文档
  33. super.startDocument();
  34. personList = new ArrayList<Person>();
  35. }
  36. public void endDocument () throws SAXException {
  37. //文档解析结束
  38. super.endDocument();
  39. }
  40. public void startElement (String uri,attributes);
  41. flag = true;
  42. if( qName.equals("person")){
  43. person = new Person();
  44. }
  45. node = qName;
  46. sb = new StringBuilder();
  47. }
  48. public void characters (char[] ch,length);
  49. if(!flag) {
  50. return;
  51. }
  52. sb.append(new String(ch,length) );
  53. }
  54. public void endElement (String uri,qName);
  55. flag = false;
  56. if( qName.equals("person")){
  57. personList.add(person);
  58. }
  59. String s = sb.toString();
  60. switch (node) {
  61. case "name":
  62. person.setName(s);
  63. break;
  64. case "sex":
  65. person.setSex(s);
  66. break;
  67. case "age":
  68. person.setAge(s);
  69. break;
  70. default:
  71. break;
  72. }
  73. }
  74. }

猜你在找的XML相关文章