zoukankan      html  css  js  c++  java
  • 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 ,在某些节点加上 之类的字符,来证实这样解析会丢失部分数据,却没有成功。它一直工作的很好??? 很多人在博文里说“,当遇到内容中有回车, 等等内容时,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.  
        }
  • 相关阅读:
    Java基础之在窗口中绘图——移动曲线的控制点(CurveApplet 3 moving the control points)
    【javascript】BOM介绍
    【javascript】Web Storage机制
    【javascript】50. Pow(x, n)
    【java】6. ZigZag Conversion
    【java】最长回文字符串(源码)
    【javascript】js实现单例模式
    【js注入】js注入
    【bootstrap】bootstrap可关闭警告框
    【h5】h5数据跨域交换postMessage用法
  • 原文地址:https://www.cnblogs.com/handsome1013/p/9493831.html
Copyright © 2011-2022 走看看