xml兩種解析方式(封裝了獲得文件和回寫)
開始時間: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解析:原理: (圖解)
將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);
}
}
}