一、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>
执行结果: