一、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、解析的一般步驟
- 創建解析器工廠對象 DocumentBuildFactory對象
- 由解析器工廠對象創建解析器對象,即DocumentBuilder對象
- 由解析器對象對指定XML文件進行解析,構建相應的DOM樹,創建Document對象,生成一個Document對象
- 以Document對象爲起點對DOM樹的節點進行查詢
- 使用Document的getElementsByTagName方法獲取元素名稱,生成一個NodeList集合
- 遍歷集合
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>
執行結果: