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

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

https://blog.csdn.net/zhutulang/article/details/37736407

 

前段时间,在写一段解析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.  
     
  28.  
    private Person person;
  29.  
     
  30.  
    private String node;
  31.  
     
  32.  
    private boolean flag = false;
  33.  
     
  34.  
    public void startDocument () throws SAXException {
  35.  
    //开始解析文档
  36.  
    super.startDocument();
  37.  
    personList = new ArrayList<Person>();
  38.  
    }
  39.  
     
  40.  
    public void endDocument () throws SAXException {
  41.  
    //文档解析结束
  42.  
    super.endDocument();
  43.  
    }
  44.  
     
  45.  
    public void startElement (String uri, String localName, String qName, Attributes attributes) throws SAXException {
  46.  
    //开始解析节点
  47.  
    super.startElement(uri, localName, qName, attributes);
  48.  
    flag = true;
  49.  
    if( qName.equals("person")){
  50.  
    person = new Person();
  51.  
    }
  52.  
    node = qName;
  53.  
    }
  54.  
     
  55.  
    public void characters (char[] ch, int start, int length) throws SAXException {
  56.  
    //保存节点内容
  57.  
    super.characters(ch, start, length);
  58.  
     
  59.  
    if(!flag) {
  60.  
    return;
  61.  
    }
  62.  
     
  63.  
    String s = new String(ch, start, length);
  64.  
    switch (node) {
  65.  
    case "name":
  66.  
    person.setName(s);
  67.  
    break;
  68.  
    case "sex":
  69.  
    person.setSex(s);
  70.  
    break;
  71.  
    case "age":
  72.  
    person.setAge(s);
  73.  
    break;
  74.  
    default:
  75.  
    break;
  76.  
    }
  77.  
    }
  78.  
     
  79.  
    public void endElement (String uri, String localName, String qName) throws SAXException {
  80.  
    //结束解析节点
  81.  
    super.endElement(uri, localName, qName);
  82.  
    flag = false;
  83.  
    if( qName.equals("person")){
  84.  
    personList.add(person);
  85.  
    }
  86.  
    }
  87.  
    }

当然,就解析上面的那段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.  
      }

转载于:https://www.cnblogs.com/handsome1013/p/9493831.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值