关于JAXP、DOM、SAX:
何为JAXP?
JAXP(JavaApi for Xml Programming) – sun公司的一套操作XML的API。
JAXP中分为三种解析方式:
DOM解析、SAX解析、StAX
DOM解析:一次性的将数据全部装入内存。
SAX解析:边读取边解析。
DOM、SAX、StAX关键词解释:
【DOM】:
DOM-Document Object Model-文档对像模型。是w3c组织处理xml的一种方式。
DOM的特点:
①一次将所有数据全部加载到内存中。
②对xml文档中的每一个节点都当成一个Node对像处理。包括元素、文本、属性。
③org.w3c.dom包中的Document,Element,Node。
④非常方便进行修改。
⑤已经集成在了JDK中,是Sun对xml操作的标准。
⑥缺点是当文档数据量很大时,对内存有占用很大。
【SAX】:
Sax – Simple Api for XML 。
①在读取数据时分析数据,通过事件监听器来完成。
②速度快但只适合读取数据,仅向前读取不可后退。
【StAX】:
①The Streaming API for XML基于流的XML编程接口
②StAX即可读文档也可以写文档。
③而SAX只可以读取文档。
XML解析的方式分为以下几种-图解:
DOM解析的说明:
DOM解析一次将所有的元素全部加载到内存中:如有以下XML文档(users.xml):
users.xml:
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user id="A001">
<name>Jack</name>
<age>22</age>
</user>
<user id="A002">
<name>张三</name>
<age>21</age>
</user>
</users>
【注意】由于DOM解析,一次性的将所有元素(包含属性和文本) 全部加载到内存中,所以不适用于解析大量的数据。
user.xml在内存中的DOM结构:
JAXP-DOM解析时候用到的Java包:
【org.w3c.dom】 – 关键类Document代表内存中的文档对像模型。
![]()
w3c是制定标准,具体的实现还是看sun公javax.xml.parsers【javax.xml.parse】– 关键类DocumentBuilder,文档解析对像。
【javax.xml】– 关键类Transformer,用于将内存中的文档保存到文件中。
以上三个类之间的关系:
在DOM中,所有元素都是Node的子类:
DOM解析的具体实现方式:
准备XML数据:
users.xml
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user id="A001">
<name>Jack</name>
<age>22</age>
</user>
<user id="A002">
<name>张三</name>
<age>21</age>
</user>
</users>
创建Document对象的思路:
①首先直接找到Document类,在org.w3c.dom包中找到,我们可以看到Document是一个接口,因此需要找到此接口的具体实现类或者能够返回出此类型的方法。
②因为w3c只是制定标准,具体类实现在sun公司的java包中,javax.xml.parsers。
③类 DocumentBuilderFactory构造方法是protected的,因此要找其中的static方法(newInstance() ),此方法返回此类类型,此时有了dbf对象。
④通过此对象dbf调用(newDocumentBuilder())得到DocumentBuilder类对象db。
⑤有了db对象,就可以调用此类(DocumentBuilder)中的parse(File f)方法就可以返回(Document)类对象dom。
创建Document对象代码实现:
第一步:创建工厂
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
第二步:创建解析器
DocumentBuilder db=dbf.newDocumentBuilder();
第三步:获得dom对象
Document dom=db.parse("./xml/users.xml");
第四步:通过节点(Node)或者元素(Element)方式解析DOM树
/....../
(一)通过节点(Node)方法解析DOM树:
第四步:首先获取根节点
Node rootNode=dom.getFirstChild();
第五步:接着获取此根节点的所有孩子节点
NodeList nodeList=rootNode.getChildNodes();
第六步:获取<user>标签的这个节点
Node userNode=nodeList.item(1);
第七步:获取<user>节点下的<name>节点
Node nameNode=userNode.getChildNodes().item(1)
第八步:获取此name节点的文本内容
String name=nameNode.getTextContent();
(二)通过Document中的getElementsByTagName()方法解析DOM树:
第四步:首先获取根节点:
Node root=dom.getFirstChild();
第五步:将根节点强转成Element元素类型
Element eroot=(Element) root;
第六步:通过标签名获取所有的此标签节点
NodeList userList=eroot.getElementsByTagName("user");
第七步:将某一个标签节点进行强转
Element eUser1=(Element) userList.item(0);
第八步:再逐层通过标签名获得某个元素
NodeList nameList=eUser1.getElementsByTagName("name");
Node nameNode=nameList.item(0);
String name=nameNode.getTextContent();
读取节点中的属性:
因为Node没有获取属性的方式,所以必须将Node强制向下转换成Element来处理。
使用:getAttribute(String name)来获取。
获取节点属性代码实现:
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
DocumentBuilder db=dbf.newDocumentBuilder();
Document dom=db.parse("./xml/users.xml/");
//将根节点强制转换为元素类型
Node root=dom.getFirstChild();
Element eroot=(Element) root;
NodeList userList=eroot.getElementsByTagName("user");
Element eUser1=(Element) userList.item(0);
//获取user节点中的属性id
String id=eUser1.getAttribute("id");
System.out.println("id="+id);
完整代码演示:
package cn.hncu.jaxp.dom;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* 解析XML:
* 1、解析XML的方式:JAXP(DOM、StAX)、jDom(dom4j)
* 2、如何使用?
* JDK中有两个专用于dom编程的包:
* (1)、org.w3c.dom -----w3c是制定标准,具体的实现还是看sun公司的javax.xml.parsers
* (2)、javax.xml.parsers -----sun公司具有开发出来解析的工具
*
*
* 入口方式:
* Document(来自org.w3c.dom)-->要用工厂方法获得该dom对象-->工厂方法来自sun公司(javax.xml.parsers)
*
*
*/
public class DomDemo {
/*
* 获取dom对象
*/
@Test
public void getDom() throws Exception{
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
DocumentBuilder db=dbf.newDocumentBuilder();
Document dom=db.parse("./xml/users.xml");
System.out.println(dom);//[#document: null]
}
/*
* 通过节点的方式获得name,age
*/
@Test
public void getName() throws Exception{
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
DocumentBuilder db=dbf.newDocumentBuilder();
Document dom=db.parse("./xml/users.xml");
//获得根节点
Node rootNode=dom.getFirstChild();
String rootNodeName=rootNode.getNodeName();
System.out.println("rootNodeName= "+rootNodeName);
/*
* 获得根节点的所有孩子节点:包括空白符和标签
* 【注意】:
* 1、通过Node中的getChildNodes(),返回类型为NodeList,获取当前节点的所有子节点(包括文本内容和标签节点)。
* 2、但是一般不选择这种方式的理由:文本内容尤其是空白符也是其中的孩子节点,会产生干扰!
* 3、因此最好的方式就是:通过Element下的getElementByTagName(String name)
*/
NodeList nodeList=rootNode.getChildNodes();
for(int i=0;i<nodeList.getLength();i++){
System.out.println( nodeList.item(i).getNodeName());
}
//获取第一个user节点下的name、age
Node userNode=nodeList.item(1);
String name=userNode.getChildNodes().item(1).getTextContent();
String age=userNode.getChildNodes().item(3).getTextContent();
System.out.println(name+","+age);
//获取第二个user节点下的name、age
Node userNode2=nodeList.item(3);
String name2=userNode2.getChildNodes().item(1).getTextContent();
String age2=userNode2.getChildNodes().item(3).getTextContent();
System.out.println(name2+","+age2);
}
/*
* 建议采用的方式:用Element中的getElementsByTagName(String name)
* 为了使用使用Element中的方法必须将Node强转成Element类型。
*/
@Test
public void getName2() throws Exception{
DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
DocumentBuilder db=dbf.newDocumentBuilder();
Document dom=db.parse("./xml/users.xml/");
//将根节点强制转换为元素类型
Node root=dom.getFirstChild();
Element eroot=(Element) root;
NodeList userList=eroot.getElementsByTagName("user");
Element eUser1=(Element) userList.item(0);
//获取user节点中的属性id
String id=eUser1.getAttribute("id");
System.out.println("id="+id);
//获取name
NodeList nameList=eUser1.getElementsByTagName("name");
Node nameNode=nameList.item(0);
String name=nameNode.getTextContent();
//获取age
NodeList ageList=eUser1.getElementsByTagName("age");
Node ageNode=ageList.item(0);
String age=ageNode.getTextContent();
System.out.println(name+":"+age);
}
}
运行结果:
getName()运行结果:
![]()
getName2()运行结果: