JavaEE实战——XML文档DOM、SAX、STAX解析方式详解

前言

    本文接着上一篇博客进行XML文档解析处理语法的介绍。在上一篇博客XML语法中我们提到了,XML技术在企业中主要应用在存储、传输数据和作为框架的配置文件这两块领域。本博客介绍的技术主要就是应用在通过XML进行存储和传输数据这一块。大致分为:JAXP DOM 解析、JAXP SAX 解析、XML PULL 进行 STAX 解析这三个方面。

简介

使用xml 存储和传输数据

1、通过程序生成xml
2、读取xml中数据 ---- xml 解析

XML解析方式有三种:DOM、SAX、StAX

三种解析方式对应着三种解析思想,表述如下。

什么是DOM、SAX、StAX ?

DOM Document Object Model ----- 文档对象模型 
DOM思想: 将整个xml 加载内存中,形成文档对象,所有对xml操作都对内存中文档对象进行
DOM 是官方xml解析标准
* 所以DOM是所有开发语言都支持的 ---- Java、JavaScript 都支持DOM

SAX Simple API for XML ----- XML 简单 API 

程序员为什么发明sax解析方式?? 当xml 文档非常大,不可能将xml所有数据加载到内存 
SAX 思想:一边解析 ,一边处理,一边释放内存资源 ---- 不允许在内存中保留大规模xml 数据

StAX The Stream API for XML ----- XML 流 API ---- JDK6.0新特性
STAX 是一种 拉模式 XML 解析方式,SAX 是一种 推模式 XML 解析方式(SAX性能不如STAX,STAX技术较新)

注解:
push模式:由服务器为主导,向客户端主动发送数据( 推送 )
pull模式: 由客户端为主导,主动向服务器申请数据( 轮询 )

三种解析开发包

掌握了三种思想后,程序员在实际开发中,使用已经开发好工具包 ----- JAXP 、DOM4j 、XML PULL

注解:
解析方式 与 解析开发包 关系?

解析方式是解析xml 思想,没有具体代码

解析开发包是解析xml思想具体代码实现。

JAXP 是sun官方推出实现技术 同时支持 DOM SAX STAX
DOM4j 是开源社区开源框架  支持 DOM 解析方式
XML PULL Android 移动设备内置xml 解析技术 支持 STAX 解析方式

DOM和SAX/STAX区别

|--DOM 支持回写
      |--会将整个XML载入内存,以树形结构方式存储
      |--XML比较复杂的时候,或者当你需要随机处理文档中数据的时候不建议使用
|--SAX/STAX
      |--相比DOM是一种更为轻量级的方案
      |--采用穿行方法读取 -- 文件输入流(字节、字符)读取
      |--编程较为复杂
      |--无法再读取过程中修改XML数据
注意:
当SAX和STAX 读取xml数据时,如果读取到内存数据不释放 ----- 内存中将存在整个xml文档数据(这种情况下就类似DOM 可以支持修改和回写)

DOM、SAX、STAX 在实际开发中选择?

在javaee日常开发中 ---- 优先使用DOM (编程简单)
当xml 文档数据非常多,不可能使用DOM ---造成内存溢出  ------ 优先使用STAX 
移动开发 使用 STAX ---- Android XML PULL 

JAXP DOM 解析

JAXP开发包简介

JAXP(Java API for XML Processing):
    DOM、SAX、STAX 只是XML解析方式,没有API
    JAXP是 Sun 提供的一套XML解析API,它很好的支持DOM和SAX解析方式,JDK6.0开始支持STAX解析方式,JAXP 开发包是JavaSE的一部分,它由javax.xml、org.w3c.dom 、org.xml.sax 包及其子包组成,在 javax.xml.parsers 包中,定义了几个工厂类,程序员调用这些工厂类,可以得到对xml文档进行解析的 DOM 或 SAX 的解析器对象。

JAXP 开发 进行 xml解析 软件包: 
javax.xml.parsers  存放 DOM 和 SAX 解析器 
javax.xml.stream  存放 STAX 解析相关类 
org.w3c.dom 存放DOM解析时 数据节点类
org.xml.sax 存放SAX解析相关工具类

DOM解析模型

DOM 是以层次结构组织的节点或信息片断的集合,是 XML 数据的一种树型表示
XML文档中所有的元素、属性、文本都会被解析成node节点 ---- 从而在内存中形成XML文档树型模型 ---- 所有的解析操作都围绕着这个模型进行
(属性节点不属于任何节点的父节点或者子节点!)
节点之间关系:parent、children、sibling(兄弟)


DOM 解析快速入门

1、创建 xml 文档 books.xml 
在企业实际开发中,为了简化xml 生成和解析 ---- xml 数据文件通常不使用约束的

2、使用DOM解析xml 
将整个xml文档加载到内存中 : 工厂 --- 解析器 ---解析加载 

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();//工厂
DocumentBuilder builder = builderFactory.newDocumentBuilder();//解析器
Document document = builder.parse("books.xml");//装载进内存

3、Document通过 getElementsByTagName("")  获得 指定标签的节点集合 NodeList 

通过 NodeList 提供 getLength 和 item遍历 节点集合
遍历ArrayList
for (int i=0;i<arraylist.size();i++){
   arraylist.get(i);
}

遍历NodeList
for (int i=0;i<nodelist.getLength();i++){
  nodelist.item(i);  ----- 将遍历的每个节点转换子接口类型
}

什么是 Node? 

对于xml 来说,xml所有数据都是node节点 (元素节点、属性节点、文本节点、注释节点、CDATA节点、文档节点)

Element Attr Text Comment CDATASection Document  ----- 都是 Node 子接口

Node对象提供了一系列常量来代表节点的类型(查看org.w3c.dom.Node接口源码):


当开发人员获得某个Node类型后,就可以把Node节点转换成相应的节点对象(Element、Attr、Text)。

注解:

node有三个通用API : 
      |--getNodeName():返回节点的名称
      |--getNodeType():返回节点的类型 ---- ELEMENT_NODE=1、ATTRIBUTE_NODE=2、TEXT_NODE=3
      |--getNodeValue():返回节点的值  ---- 所有元素节点value都是 null

另外,对于元素节点ELEMENT来说:

|--获得元素节点中的属性值
      |--element.getAttribute(属性名称)
|--获得元素节点内部文本内容
      |--element.getTextContent()
      |--element.getFirstChild().getNodeValue()

代码示例:

books.xml:

<?xml version="1.0" encoding="UTF-8"?>
<books>
	<book>
		<name>java编程基础</name>
		<price>80</price>
	</book>
	<book>
		<name>java高级应用</name>
		<price>100</price>
	</book>
</books>

测试程序:

package cn.itcast.dom.jaxp;

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

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

public class DOMTest {
	@Test
	// 查询 java编程基础 书 售价
	public void demo3() throws Exception {
		// 装载xml 加载内存 --- Document对象
		DocumentBuilderFactory builderFactory = DocumentBuilderFactory
				.newInstance();
		DocumentBuilder builder = builderFactory.newDocumentBuilder();
		Document document = builder.parse("books.xml");

		// 利用全局查询 锁定 每个name节点
		NodeList nodelist = document.getElementsByTagName("name");
		for (int i = 0; i < nodelist.getLength(); i++) {
			Element name = (Element) nodelist.item(i);
			if (name.getTextContent().equals("java编程基础")) {
				// 图书 找到了
				// price 是 name 节点 兄弟的兄弟,三个换行符也是子节点
				Element price = (Element) name.getNextSibling()
						.getNextSibling();
				System.out.println(price.getTextContent());
			}
		}
	}

	@Test
	// 查询 java编程基础 书 售价
	public void demo2() throws Exception {
		// 装载xml 加载内存 --- Document对象
		DocumentBuilderFactory builderFactory = DocumentBuilderFactory
				.newInstance();
		DocumentBuilder builder = builderFactory.newDocumentBuilder();
		Document document = builder.parse("books.xml");

		// 全局查询 作为程序 切入
		NodeList nodelist = document.getElementsByTagName("book");
		// 遍历 强制转换 Element
		for (int i = 0; i < nodelist.getLength(); i++) {
			Element book = (Element) nodelist.item(i);
			// 找 哪个 book 节点 当中 name 节点值 java编程基础 ---- 查找book的name 子节点
			NodeList chidren = book.getChildNodes();
			//System.out.println(chidren.getLength());//注意:回车、空格也是子元素
			Element name = (Element) chidren.item(1); // book的第二个子节点就是name
			if (name.getTextContent().equals("java编程基础")) {
				// 当前for循环 这本书 是目标图书
				// 打印图书价格 price 是 book 第四个子节点
				Element price = (Element) chidren.item(3);
				System.out.println(price.getTextContent());
			}
		}
	}

	@Test
	public void demo1() throws Exception {
		// 通过DOM 解析 XML --- 载入整个xml 工厂 -- 解析器 --- 加载

		// 构造工厂
		DocumentBuilderFactory builderFactory = DocumentBuilderFactory
				.newInstance();
		// 通过工厂 获得解析器
		DocumentBuilder builder = builderFactory.newDocumentBuilder();

		// 使用解析器 加载 xml文档
		Document document = builder.parse("books.xml");

		// Document代表整个xml 文档,通过操作Document,操作xml数据

		// 将所有图书名称打印出来
		// 这里 nodelist 代表节点的集合
		// 查询所有 name标签
		NodeList nodelist = document.getElementsByTagName("name");
		// 遍历集合中 所有 node
		System.out.println("图书name节点数量:" + nodelist.getLength());
		for (int i = 0; i < nodelist.getLength(); i++) {
			// 获得每个 node 节点
			Node node = nodelist.item(i); // 这里每个node 都是 <name></name> ---- 元素
			Element e = (Element) node; // 将 节点转换为 子类型 节点
			System.out.println(e.getNodeName()); // 节点元素名称
			System.out.println(e.getNodeType()); // 节点元素 类型
			System.out.println(e.getNodeValue()); // 节点元素 值
			// 输出 name 元素 子节点文本节点值
			System.out.println(e.getFirstChild().getNodeValue());
			System.out.println(e.getTextContent());
			System.out.println("------------------------------------");
		}
	}
}

DOM 编程思路小结

1、装载XML文档 ---- Document (工厂--解析器--解析加载)

2、Document 获得指定元素 ----- getElementsByTagName (返回 NodeList)
3、遍历NodeList 获得 每个 Node
4、将每个Node 强制转换 Element 
5、通过元素节点API 操作属性和文本内容 
      |--getAttribute  获得属性值
      |--getTextContent 获得元素内部文本内容

这其中,第一步<

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值