DOM SAX和PULL解析

来源:互联网 发布:淘宝查优惠券插件 编辑:程序博客网 时间:2024/05/21 15:41
  • 其树结构如下


    树结构 .png

  • XML节点解释
    XML文件是由节点构成的。它的第一个节点为“根节点”。一个XML文件必须有且只能有一个根节点,其他节点都必须是它的子节点。



    this 代表整个XML文件,它的根节点就是 this.firstChild 。 this.firstChild.childNodes 则返回由根节点的所有子节点组成的节点数组。


  •   每个子节点又可以有自己的子节点。节点编号由0开始,根节点的第一个子节点为 this.firstChild.childNodes[0],它的子节点数组就是this.firstChild.childNodes[0].childNodes 。



    根节点第一个子节点的第二个子节点 this.firstChild.childNodes[0].childNodes[1],它返回的是一个XML对象(Object) 。这里需要特别注意,节点标签之间的数据本身也视为一个节点 this.firstChild.childNodes[0].childNodes[1].firstChild ,而不是一个值。



    我们解析XML的最终目的当然就是获得数据的值:this.firstChild.childNodes[0].childNodes[1].firstChild.nodeValue 。

    请注意区分:节点名称(<性别></性别>)和之间的文本内容(男)可以当作是节点,也可以当作是一个值

    节点:
    名称:this.firstChild.childNodes[0].childNodes[1]
    文本内容:this.firstChild.childNodes[0].childNodes[1].firstChild

    值:
    名称:this.firstChild.childNodes[0].childNodes[1].nodeValue
    (节点名称有时也是我们需要的数据)
    文本内容:this.firstChild.childNodes[0].childNodes[1].nodeName

    在了解完XML之后,是时候来学下如何进行XML的解析了

    XML解析

    解析XML,即从XML中提取有用的信息

    解析方式

    基于文档驱动方式

    • 主流方式:DOM方式
    • 简介:XML DOM(XML Document Object Model),XML文件对象模型,定义了访问操作xml文档元素的方法和接口
    • 工作原理: DOM是基于树形结构的的节点的文档驱动方法。使用DOM对XML文件进行操作时,首先解析器读入整个XML文档到内存中,然后解析全部文件,并将文件分为独立的元素、属性等,以树结构的形式在内存中对XML文件进行表示,开发人员通过使用DOM API遍历XML树,根据需要修改文档或检索所需数据
    DOM解析
    • 假设需要解析的XML文档如下(subject.xml)
      <?xml version ="1.0" encoding="UTF-8"?>`<code><language id="1">  <name>Java</name>  <usage>Android</usage></language><language id="2">  <name>Swift#</name>  <usage>iOS</usage></language><language id="3">  <name>Html5</name> <usage>Web</usage></language></code>
    • 核心代码
      public static List<subject> getSubjectList(InputStream stream) { tv = (TextView)findViewById(R.id.tv);      try {          //打开xml文件到输入流          InputStream stream = getAssets().open("subject.xml");          //得到 DocumentBuilderFactory 对象          DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();          //得到DocumentBuilder对象          DocumentBuilder builder = builderFactory.newDocumentBuilder();          //建立Document存放整个xml的Document对象数据          Document document = builder.parse(stream);          //得到 XML数据的"根节点"           Element element = document.getDocumentElement();          //获取根节点的所有language的节点          NodeList list = element.getElementsByTagName("language");           //遍历所有节点          for (int i= 0;i<=list.getLength();i++){          //获取lan的所有子元素              Element language = (Element) list.item(i);          //获取language的属性(这里即为id)并显示              tv.append(lan.getAttribute("id")+"\n");        //获取language的子元素 name 并显示                       tv.append(sub.getElementsByTagName("name").item(0).getTextContent()+"\n");       //获取language的子元素usage 并显示                    tv.append(sub.getElementsByTagName("usage").item(0).getTextContent()+"\n");          }

    总结Dom解析的步骤

    1、调用 DocumentBuilderFactory.newInstance() 方法得到 DOM 解析器工厂类实例。
    2、调用解析器工厂实例类的 newDocumentBuilder() 方法得到 DOM 解析器对象
    3、调用 DOM 解析器对象的 parse() 方法解析 XML 文档得到代表整个文档的 Document 对象。

    基于事件驱动

    • 主流方式:SAX、PULL方式
    • 解析方式:可直接根据需要读取所需的JSON数据,不需要像DOM方法把文档先入到内存中
    PULL解析
    • 工作原理:PULL的解析方式与SAX解析类似,都是基于事件的模式。
      PULL提供了开始元素和结束元素。当某个元素开始时,我们可以调用parser.nextText从XML文档中提取所有字符数据,与SAX不同的是,在PULL解析过程中触发相应的事件调用方法返回的是数字,且我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法从而执行代码。当解释到一个文档结束时,自动生成EndDocument事件。
    • 核心代码

      public class MainActivity extends Activity {  private EditText et;  private Button myButton;  @Override  public void onCreate(Bundle savedInstanceState) {      super.onCreate(savedInstanceState);      setContentView(R.layout.activity_main);       myButton = (Button) this.findViewById(R.id.btn01);      et = (EditText) this.findViewById(R.id.edittext01);      myButton.setOnClickListener(new OnClickListener() {      //可变字符序列,比StringBuffer块          StringBuilder sb = new StringBuilder("");          Resources res = getResources();          XmlResourceParser xrp = res.getXml(R.xml.subject);          @Override          public void onClick(View v) {              int counter = 0;              try {                  // 判断是否到了文件的结尾                  while (xrp.getEventType() != XmlPullParser.END_DOCUMENT) {                      //文件的内容的起始标签开始,这里的起始标签是subject.xml文件里面<subjects>标签下面的第一个标签                      int eventType=xrp.getEventType();                      switch (eventType) {                          case XmlPullParser.START_DOCUMENT:                              break;                          case  XmlPullParser.START_TAG:                              String tagname = xrp.getName();                              if (tagname.endsWith("language")) {                                  counter++;                                  sb.append("这是第" + counter + "种语言"+"\n");                                  //可以调用XmlPullParser的getAttributte()方法来获取属性的值                                  sb.append("语言id是:"+xrp.getAttributeValue(0)+"\n");                              }                              else if(tagname.equals("name")){                                  //可以调用XmlPullParser的nextText()方法来获取节点的值                                  sb.append("语言名称是:"+xrp.nextText()+"\n");                              }                              else if(tagname.equals("teacher")){                                  sb.append("用途是:"+xrp.nextText()+"\n");                              }                              break;                          case XmlPullParser.END_TAG:                              break;                          case XmlPullParser.TEXT:                              break;                      }                      //解析下一个事件                      xrp.next();                  }                  //StringBuilder要调用toString()方法并显示                  et.setText(sb.toString());              } catch (XmlPullParserException e) {              } catch (IOException e) {                  e.printStackTrace();              }          }      });  }

    SAX解析

    • 工作原理:基于事件驱动,在读取XML文档内容时,事件源顺序地对文档进行扫描,当扫描到文档的开始与结束(Document)标签、节点元素的开始与结束(Element)标签时,直接调用对应的方法,并将状态信息以参数的形式传递到方法中,然后我们可以依据状态信息来执行相关的自定义操作。

    同样是采用事件驱动进行解析,但相比pull解析方法,采用SAX方式进行XML解析可能会较为复杂,这里就不作实例展示,有兴趣的童鞋们可以自己去尝试下,毕竟实践出真知

    DOM、SAX、PULL三类方式对比

    DOM方式

    • 原理:基于文档驱动,是先把dom全部文件读入到内存中,构建一个主流内存的树结构,然后使用DOM的API遍历所有数据,调用API检索想要的数据和操作数据。
      所以,DOM方式的优缺点是:
    • 特点:
      优点:整个文档树存在内存中,可对XML文档进行操作:删除、修改等等;可多次访问已解析的文档;由于在内存中以树形结构存放,因此检索和更新效率会更高。;
      缺点:解析 XML 文件时会将整个 XML 文件的内容解析成树型结构存放在内存中并创建新对象,比较消耗时间和内存;
    • 使用情境
      对于像手机这样的移动设备来讲,内存是非常有限的,在XML文档比较小、需要对解析文档进行一定的操作且一旦解析了文档需要多次访问这些数据的情况下可以考虑使用DOM方式,因为其检索和解析效率较高

    SAX方式

    • 原理:基于事件驱动,在读取XML文档内容时,事件源顺序地对文档进行扫描,当扫描到文档的开始与结束(Document)标签、节点元素的开始与结束(Element)标签时,直接调用对应的方法,并将状态信息以参数的形式传递到方法中,然后我们可以依据状态信息来执行相关的自定义操作。
    • 特点:
      优点:解析效率高、占存少、灵活性高
      缺点:解析方法复杂(API接口复杂),代码量大;可拓展性差:无法对 XML 树内容结构进行任何修改
    • 使用情境
      适用于需要处理大型 XML 文档、性能要求较高、不需要对解析文档进行修改且不需要对解析文档多次访问的场合

    PULL方式

    • 原理:PULL的解析方式与SAX解析类似,都是基于事件的模式。
      PULL提供了开始元素和结束元素。当某个元素开始时,我们可以调用parser.nextText从XML文档中提取所有字符数据,与SAX不同的是,在PULL解析过程中触发相应的事件调用方法返回的是数字,且我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法从而执行代码。当解释到一个文档结束时,自动生成EndDocument事件。
    • 特点:
      优点:SAX的优点PULL都有,而且解析方法比SAX更加简单
      缺点:可拓展性差:无法对 XML 树内容结构进行任何修改

    • 使用情境
      适用于需要处理大型 XML 文档、性能要求较高、不需要对解析文档进行修改且不需要对解析文档多次访问的场合

    同样的使用情景,在SAX和PULL解析方法中,更加推荐PULL方法

    总结

    本文对现今主流的数据传输格式XML进行了简单的介绍,希望大家实践出真知哦!

    0 0
    原创粉丝点击