開始時間:2018年10月6日13:16:37
結束時間:2018年10月6日14:26:25
累計時間:1
xml解析:
這一篇挺好 https://blog.csdn.net/CristianoJason/article/details/51777853
但我習慣自己寫,對自己提升幫助更大,再者對他做一個補充吧。
xml的解析有兩種: dom 解析: sax 解析:
1:dom解析:原理: (圖解)
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX4NGRNNTRU5EeRpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2LcRHelR3LcJzLctmch1mclRXY39DMyYzM1kDNxIzNykDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
将xml 根據xml的層級結構,将xml文檔在記憶體當中配置設定成一個樹形結構。
把每個标簽,屬性, 文本都封裝成了一個對象。
有了對象就可以使用對象的屬性和方法來解析xml文檔,步驟如下:
sun: jaxp dom解析:
(1)元素節點的查詢操作: 查詢所有的。
(2)節點元素的添加操作: (記憶體當中完成,document 回寫)
(3)節點的删除操作:
步驟:
a:解析器的工廠: DocumentBuilderFactory
b:獲得解析器: DocumentBuilder
c:解析: 獲得整個文檔: Document
d:獲得要删除的節點:
e:獲得删除節點的父節點:
f:父節點執行删除操作:
g: 回寫:
(4)節點元素的修改: 内容的修飾: 51---15
步驟:
a:通過工具類 獲得整個文檔:
b:獲得要修改的節點:
c:調用對方法 對内容進行修改。
d: 回寫
(5) 節點元素的替換操作: age ---> school
a: 工具類獲得文檔: document
b: 獲得要替換的元素的節點:
C: 建立一個新的節點:
建立文本節點:
将文本節點追加到新節點。
D: 獲得要是替換節點的父節點。
e: 父節點執行替換操作:
f: 回寫:
2: 解析器:
不同的公司 廠商提供了不同的解析器:
sun: 針對dom解析和sax解析 提供jaxp (JDK)
jdom 針對dom 和 sax 提供的解析器: jdom
dom4J: 針對dom 和 sax 供的解析器 : dom4J(重點) 主流
3: 針對sun公司提供的jaxp、解析器實作對xml的解析
解析步驟:
(1) 建立一個xml檔案: persons xml檔案
(2)解析persons檔案:
a: 獲得解析器: 檢視JDK的文檔: javax.xml.parsers 包當中:
DocumentBuilder : dom解析的解析器: 抽象的類,不能直接執行個體化。 通過 工廠獲得執行個體
DocumentBuilderFactory: 解析器的工廠類:抽象類: 通過靜态方法獲得執行個體。
Document: 文檔對象:
NodeList: 節點的集合對象:
Node : 節點: 父對象:
需求: 節點内容的查找
節點内容的添加
删除
實作代碼如下:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
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;
import org.w3c.dom.Text;
/*
* 使用sun公司提供的jaxp、
* 解析器進行解析 xml檔案:
*
* //需求: 查詢所有的name的值:
*
* 步驟:
* 1: 獲得解析器工廠。 DocumentBuilderFactory.newInstance()
* 2: 通過工廠獲得解析器: DocumentBuilder
* 3: 獲得Document對象: 通過解析器的parse(String url )
* 4: 通過document對象的方法:獲得所有的name 節點: 傳回的是NodeList
* 5: 周遊NodeList 獲得每一個Node 。
* 6: 使用Node API方法獲得文本的内容: getTextContent()
*/
public class DomParsers {
//獲得了persons 當中所有name的值:
@Test
public void test01()throws Exception{
//獲得解析器的工廠:L
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//獲得一個解析器:
DocumentBuilder builder = factory.newDocumentBuilder();
// 獲得整個Document文檔: 獲得了整個樹 就獲得了樹當中所有的節點:
Document document = builder.parse("src/persons.xml");
//使用doucment對象的API方法: 獲得所有的name節點,傳回的是一個list集合:
NodeList list = document.getElementsByTagName("name");
//周遊集合:
for(int i=0; i<list.getLength(); i++){
Node node = list.item(i);
// node 是獲得name 對應的标簽節點: 、
String content = node.getTextContent();
System.out.println(content);
}
}
// 獲得第二個name的值:
@Test
public void test02()throws Exception{
//獲得解析器的工廠:L
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//獲得一個解析器:
DocumentBuilder builder = factory.newDocumentBuilder();
// 獲得整個Document文檔: 獲得了整個樹 就獲得了樹當中所有的節點:
Document document = builder.parse("src/persons.xml");
//使用doucment對象的API方法: 獲得所有的name節點,傳回的是一個list集合:
NodeList list = document.getElementsByTagName("name");
Node nameEle = list.item(1);
String name = nameEle.getTextContent();
System.out.println(name);
}
// 實作節點元素的添加操作: <person> <sex>
@Test
public void test03()throws Exception{
//獲得解析器的工廠:L
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//獲得一個解析器:
DocumentBuilder builder = factory.newDocumentBuilder();
// 獲得整個Document文檔: 獲得了整個樹 就獲得了樹當中所有的節點:
Document document = builder.parse("src/persons.xml");
//建立一個新的節點:
Element sexEle = document.createElement("sex");//在記憶體當中形成了: <sex> </sex>
//檔案文本節點:
Text text = document.createTextNode("weizhi");// weizhi
//将文本節點追加到 sexEle後L
sexEle.appendChild(text); // <sex> weizhi </sex>
//獲得第一個person對象:
Node personFirst = document.getElementsByTagName("person").item(0);
// 将建立的新标簽追加在 personFirst 後:
personFirst.appendChild(sexEle);
//===================================以上所有的操作都是在記憶體當中完成: 需要将記憶體的document 寫出到外部的檔案當中:
// 獲得工廠:TransFormerFactory、
TransformerFactory f = TransformerFactory.newInstance();
Transformer transFormer = f.newTransformer();
//調用api 實作document的回寫: transform(Source xmlSource, Result outputTarget)
transFormer.transform(new DOMSource(document), new StreamResult("src/persons.xml") );
}
}
二: dom 和 sax 解析的差別:
dom: 整個文檔封裝成一棵樹形結構, 把文檔當中所有的内容都封裝了對象。
使用對象的方法和屬性對樹進行進行操作。
所有的内容:
标簽節點:
屬性節點:
文檔節點:
優點: 友善節點元素的增删改查操作。
弊端: 當xml檔案過大,全部加載到記憶體當中,容易造成記憶體溢出。
sax解析: 原理: 采用事件驅動的形式進行解析》
特點: 邊讀邊解析。
優點: 不會造成記憶體溢出。 采用事件驅動的形式,邊讀邊解析。
弊端: 隻能查詢操作,不能進行增删改操作。
sax解析的步驟:
解析器:
SAXParser 抽象類,不能直接執行個體化。 通過工廠獲得。
SAXParserFactory 獲得解析器的工廠類, 抽象的類,不能直接執行個體化。 通過本類的靜态方法獲得。
例子如下:
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.junit.Test;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/*
* 使用 sax 解析 解析文檔:
*/
public class SaxParseDoc {
private static final String PATH ="src/persons.xml";
//讀取了檔案的内容:
@Test
public void test01() throws ParserConfigurationException, SAXException, IOException{
//獲得解析器工廠:
SAXParserFactory factory = SAXParserFactory.newInstance();
//獲得解析器:
SAXParser parser = factory.newSAXParser();
//解析文檔: 第一個參數是一個來源: 對誰進行解析:
// 參數二: 是一個事件處理器:
parser.parse(PATH, new MyDefaultHander());
}
//擷取所有的name的值:
@Test
public void test02() throws ParserConfigurationException, SAXException, IOException{
//獲得解析器工廠:
SAXParserFactory factory = SAXParserFactory.newInstance();
//獲得解析器:
SAXParser parser = factory.newSAXParser();
//解析文檔: 第一個參數是一個來源: 對誰進行解析:
// 參數二: 是一個事件處理器:
parser.parse(PATH, new MyDefaultHander());
}
}
//MyDefaultHander 具備處理器的功能:
class MyDefaultHander extends DefaultHandler{
//定義一個标志位:
private boolean flag= false;
//定義一個計數器:
int count=0;
//子類對父類進行方法的重寫:
//用來讀取開始标簽
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// qName : 标簽的名稱:
if("name".equals(qName)){
flag=true;
count++;
}
}
// 用來讀取文本内容的: 将讀取的文本的内容封裝到了字元數組當中
public void characters(char[] ch, int start, int length)
throws SAXException {
if(flag && count==1){
System.out.print(new String(ch, start, length));
}
}
// 用來讀取結束标簽:
public void endElement(String uri, String localName, String qName)
throws SAXException {
flag=false;
}
}
其中 獲得文檔對象和回寫操作多次用到,對其進行封裝:
(工具類封裝一般在util包下面)
package com.yidongxueyuan.util;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
/**
* 針對sun公司提供的 jaxp 解析器 提供的工具類:
* (1) 獲得Document文檔: 、
* (2)回寫的方法:
* @author Mrsun
*
*/
public class JaxpUtils {
/**
* 獲得整個document文檔對象:
* @return 文檔對象:
*/
public static Document getDocument(String path){
try {
//獲得解析器的工廠:L
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//獲得一個解析器:
DocumentBuilder builder = factory.newDocumentBuilder();
// 獲得整個Document文檔: 獲得了整個樹 就獲得了樹當中所有的節點:
Document document = builder.parse(path);
return document;
} catch (Exception e) {
throw new RuntimeException("解析文檔失敗");
}
}
/**
* 将記憶體當中的樹寫出到外部的檔案當中:
* @param document 文檔對象
* @param path 指定的目的:
*/
public static void writer2File(Document document, String path ){
try {
TransformerFactory f = TransformerFactory.newInstance();
Transformer transFormer = f.newTransformer();
//調用api 實作document的回寫: transform(Source xmlSource, Result outputTarget)
transFormer.transform(new DOMSource(document), new StreamResult(path) );
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}