sax和dom方式解析xml

一、sax解析xml

1.1、sax概述

SAX解析方式會逐行地去掃描XML文檔,當遇到標籤時會觸發解析處理器,採用事件處理的方式解析XML (Simple API for XML) ,不是官方標準,但它是 XML 社區事實上的標準,幾乎所有的 XML 解析器都支持它。

SAX的優點:

  • 解析速度快
  • 佔用內存少

SAX的缺點:

  • 只能讀取XML,無法修改XML
  • 流式訪問,無法隨機訪問某個標籤(節點)

SAX解析適用場合:

  • 對於只需從xml讀取信息而無需修改xml

1.2、解析的一般步驟

  • 得到xml文件對應的資源,可以是xml的輸入流,文件和uri
  • 得到SAX解析工廠(SAXParserFactory)
  • 由解析工廠生產一個SAX解析器(SAXParser)
  • 傳入輸入流和handler(一般繼承DefaultHandler,實現自己的回調方法)給解析器,調用parse()解析

1.3、解析實例

package org.apache.ibatis.lgtest;

import org.junit.jupiter.api.Test;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.FileInputStream;
import java.text.MessageFormat;

/**
 * @author lg
 * @description java sax test
 * @create 2019-07-05
 **/
public class SaxTest {

  @Test
  public void sax() throws Exception {
    //獲取輸入流
    FileInputStream fileInputStream = new FileInputStream(SaxTest.class.getClassLoader().getResource("./resources/nodelet_test.xml").getPath());

    //獲取sax解析器工廠
    SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();

    //構建解析器
    SAXParser saxParser = saxParserFactory.newSAXParser();

    MyXmlHandler myXmlHandler = new MyXmlHandler();
    //解析xml
    saxParser.parse(fileInputStream, myXmlHandler);

    System.out.println(MessageFormat.format("僱員[{0}]信息:weight爲{1},height爲{2}", myXmlHandler.getId(), myXmlHandler.getWeight(), myXmlHandler.getHeight()));
  }
}

class MyXmlHandler extends DefaultHandler {

  /**
   * 當前標籤
   */
  private String currentTag = "";

  private boolean currentTagEnd = true;

  private String height = "";
  private String weight = "";
  private String id = "";

  @Override
  public void startDocument() throws SAXException {
    //開始解析xml事件回調
    System.out.println("開始解析xml");
  }

  @Override
  public void endDocument() throws SAXException {
    //xml解析結束事件回調
    System.out.println("xml解析結束");
  }

  @Override
  public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
    //開始解析xml節點的事件回調

    // uri:命名空間
    // localName:不帶命名空間前綴的標籤名
    // qName:帶命名空間的標籤名

    currentTag = qName;
    currentTagEnd = false;
    System.out.println("解析到了節點:" + qName);

    if (qName.equals("employee")) {
      id = attributes.getValue(0);
    }
  }

  @Override
  public void endElement(String uri, String localName, String qName) throws SAXException {
    //xml節點解析結束事件回調
    System.out.println("節點:" + qName + "解析結束");
    currentTagEnd = true;

  }

  @Override
  public void characters(char[] ch, int start, int length) throws SAXException {
    //解析到文本節點的時候會回調此方法
    String text = new String(ch, start, length);
    switch (currentTag) {
      case "weight":
        if (!currentTagEnd) {
          this.weight = text;
        }
        break;
      case "height":
        if (!currentTagEnd) {
          this.height = text;
        }
        break;
      default:
        break;
    }

  }

  public String getHeight() {
    return height;
  }

  public String getWeight() {
    return weight;
  }

  public String getId() {
    return id;
  }
}


用到的xml文件

<employee id="A10004">
  <height units="ft">5.8</height>
  <weight units="lbs">200</weight>
</employee>

結果:
在這裏插入圖片描述

1.4、DefaultHandler回調方法的順序(詳情請參考第一個引用)

一:sax中DefaultHandler解析XML總體過程

    startDocument--->具體讀到某個node(非根node和根node)的解析過程 --->endDocument 。

二:DefaultHandler 解析XML 的非根node是按順序的四步(不管當前node是ElementNode[可有屬性]還是TextNode)(非根node本測試程序如 person,name,age):

    第一步:startElement.
    第二步 :  characters   
    第三步 :  endElement    
    第四步 :  characters   

三:DefaultHandler 解析XML 的根node是按順序的三步(本測試程序中根node爲 persons):

    第一步:startElement.  
    第二步 :  characters     
    第三步 :  endElement             

二、dom解析xml

2.1、dom概述

DOM將整個XML文件加載到內存中,並構建出節點樹;應用程序可以通過遍歷節點樹的方式來解析XML文件中的各個節點、屬性等信息;
這種方式便於對XML節點的添加修改等,而且解析也很方便,然後它比較耗費內存,解析速度也不快。

2.2、解析的一般步驟

  1. 創建解析器工廠對象 DocumentBuildFactory對象
  2. 由解析器工廠對象創建解析器對象,即DocumentBuilder對象
  3. 由解析器對象對指定XML文件進行解析,構建相應的DOM樹,創建Document對象,生成一個Document對象
  4. 以Document對象爲起點對DOM樹的節點進行查詢
  5. 使用Document的getElementsByTagName方法獲取元素名稱,生成一個NodeList集合
  6. 遍歷集合

2.3、例子

package org.apache.ibatis.lgtest;

import org.junit.jupiter.api.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.FileInputStream;
import java.text.MessageFormat;

/**
 * @author lg
 * @description
 * @create 2019-07-11
 **/
public class DomTest {

  @Test
  public void testDom() throws Exception {
    //構建解析器工廠
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

    //構建解析器
    DocumentBuilder documentBuilder = factory.newDocumentBuilder();

    FileInputStream inputStream = new FileInputStream(DomTest.class.getClassLoader().getResource("resources/nodelet_test.xml").getPath());
    //使用解析器構建Document對象
    Document document = documentBuilder.parse(inputStream);

    //獲取根節點
    Element root = document.getDocumentElement();

    NodeList fNameNode = root.getElementsByTagName("first_name");
    NodeList lNameNode = root.getElementsByTagName("last_name");

    String id = root.getAttribute("id");

    System.out.println(MessageFormat.format("工號爲{0}的員工 first_name是{1},last_name是{2}", id, fNameNode.item(0).getNodeValue(), lNameNode.item(0).getNodeValue()));

  }
}

xml

<employee id="A10004">
  <blah something="that"/>
  <first_name>Jim</first_name>
  <last_name>Smith</last_name>
  <birth_date>
    <year>1970</year>
    <month>6</month>
    <day>15</day>
  </birth_date>
  <height units="ft">5.8</height>
  <weight units="lbs">200</weight>
  <active>true</active>
</employee>

執行結果:
在這裏插入圖片描述

引用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章