天天看點

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文檔在記憶體當中配置設定成一個樹形結構。  

                    把每個标簽,屬性, 文本都封裝成了一個對象。 

   有了對象就可以使用對象的屬性和方法來解析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);
		}
	}

	
}