1. 程式人生 > >xml兩種解析方式(封裝了獲得文件和回寫)

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);
		}
	}

	
}