java自學之路-----XML_解析技術

xml解析方式:

dom(Document Object Model):文檔對象模型,是w3c組織解析xml的一種方式

sax(Simple API for XML):不是官方標準,但他是xml社區的標準,幾乎所有的xml解析器都支持

xml的解析開發包:jaxp(sun),jdom(開源組織)和dom4j(開源組織)

dom和sax的區別{

1.dom解析的優點是對文檔crud比較方便,缺點是佔用內存比較大。原理:因爲解析的時候需要將整個文檔加載到內存,將文檔的節點作爲對象,在內存建立一個對象關係表

2.sax解析的優點是佔用內存少,解析速度快,缺點是隻適合作爲文檔的讀取,不適合作爲文檔的crud。原理:讀取一行解析一行的方式

}


JAXP{

1.是j2se的一部分,由javax.xml、org.w3c.dom、org.xml.sax包及其子包組成

2.在javax.xml.parsers包中,定義了幾個工廠類,程序員可以通過調用工廠類得到xml文檔的dom、sax的解析器,從而對xml文檔進行解析


dom解析{讀取完文檔再解析

1.獲得javax.xml.parsers包中的DocumentBuilderFactory(工廠模式,不可實例化,可以通過公共方法獲得實例)

2.創建dom模式的解析器對象

3.解析xml文檔,獲得文檔對象

4.通過文檔對象可以通過標籤名獲得文檔內的所有標籤

//		1.創建工廠
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//		2.通過工廠獲得解析器對象
		DocumentBuilder builder = factory.newDocumentBuilder();
//		3.通過對象解析文件,獲得代表文檔的document對象
		Document document = builder.parse("src/book.xml");
		
//		獲取標籤,返回多個節點組成的list,標籤名相同
		NodeList list = document.getElementsByTagName("書名");
//		獲取list中的節點,所有從0開始.獲取第二個名爲書名的節點
		Node node = list.item(1);
//		得到該節點的內容
		String content = node.getTextContent();

5.通過標籤的節點又可以獲得該標籤的子標籤:getChildNodes();

//		獲得指定標籤下的所有標籤
	public void list(Node node){
//		由於xml文檔中的換行符也會作爲節點的子節點。所以先判斷該節點是否爲標籤
		if(node instanceof Element){
			System.out.println(node.getNodeName());
		}
//		1.獲取該標籤下的所有子標籤
		NodeList list = node.getChildNodes();
//		2.遍歷子標籤,在獲得它的子標籤(遞歸)
		for (int i = 0; i < list.getLength(); i++) {
			Node child = list.item(i);
			list(child);			
		}		
	}

6.可以將節點轉爲標籤對象,再使用屬性名來獲取屬性值

		Element book = (Element) document.getElementsByTagName("書").item(0);
		book.getAttribute("name");

7.以下幾個都是對內存中的文檔對象進行修改,並未修改xml文檔,就需要使用javax.xml.transformer包中的Transform方法把代表xml文件的document對象轉換成某種格式後再輸出到xml文件中,這個類的轉換方法需要接受源(通過DOMSource關聯要轉換的document對象)和目的(用StreamResult對象表示數據的目的地)

8.使用文檔對象創建標籤:createElement("..."),爲標籤賦值之後,綁定在一個標籤上

//	添加標籤到文檔中(添加指定的位置:insertBefore(newChild,refChild))
	public void add() throws Exception{
//		1.獲得文檔對象
		Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/book.xml");
//		2.創建一個售價的標籤
		Element price = document.createElement("售價");
//		3.爲該標籤添加內容
		price.setTextContent("49.00元");
//		4.將該標籤放在第一個名爲“書”的標籤下
		Element book = (Element) document.getElementsByTagName("書").item(0);
		book.getAttribute("name");
		book.appendChild(price);
//		5.由於以上代碼知識將內存中的文檔更新了,需要將內存中的文檔更新到xml文檔
			//先獲生產轉換對象的工廠
		TransformerFactory factory = TransformerFactory.newInstance();
			//得到轉化對象
		Transformer ts = factory.newTransformer();
			//將document對象封裝成源,xml位置流封裝成目的地
		DOMSource source = new DOMSource(document);//直接使用創建對象的方法封裝document
		StreamResult result = new StreamResult(new FileOutputStream("src/book.xml"));//將xml文件的路徑封裝成目的流
			//調用轉化方法
		ts.transform(source, result);
	}

9.獲得標籤的element對象,使用setAttribute()設置屬性

//	給標籤添加一個屬性
	public void addAttr() throws Exception{
//		1.獲得文檔對象
		Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/book.xml");
//		2.獲得要添加屬性的標籤,第一本書
		Element book = (Element) document.getElementsByTagName("書").item(0);
//		3.爲該節點添加屬性
		book.setAttribute("name", "java編程");
//		4.將內存中的文檔更新到xml文件
		TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document), new StreamResult("src/book.xml"));
	}

10.獲得標籤的element對象,使用setTextContent()修改標籤的內容

//	修改標籤的內容
	public void update() throws Exception{
//		1.獲得文檔對象
		Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/book.xml");
//		2.獲得要修改內容的標籤對象
		Element book = (Element) document.getElementsByTagName("書").item(0);
//		3.修改內容
		book.setTextContent("哈哈哈");
//		4.將內存中的文檔更新到xml文件
		TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document), new StreamResult(new FileOutputStream("src/book.xml")));
	}

11.獲得old的父標籤Element對象,再使用removeChild(old)來刪除old節點

//	刪除某個標籤
	public void delete() throws Exception{
//		1.獲得文檔對象
		Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/book.xml");
//		2.獲得要刪除的書的標籤對象
		Element book = (Element) document.getElementsByTagName("書").item(0);
//		3.獲得書的父標籤刪除。
		book.getParentNode().removeChild(book);
//		4.將內存中的文檔更新到xml文件
		TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document), new StreamResult(new FileOutputStream("src/book.xml")));
	}

注意:dom解析下,xml文檔的每一個組成部分都用一個對象表示,例如標籤的Element和屬性的Attr,但不管什麼對象都是Node的子類,所以標籤可以當做節點來對待
}

sax解析{邊讀取邊解析

採用事件處理方式解析xml文件,該技術涉及兩個部分:

解析器:使用JAXP的API創建,創建出解析器後就可以通過讀取器去解析某個 xml文檔。在解析的時候,只要解析到文件的一個組成部分就會去調用事件處理器的一個方法,在調用方法的時候會將當前解析的xml文件內容作爲方法的參數傳給事件處理器。

	public void parse() throws Exception{
//	1.獲得解析器工廠
	SAXParserFactory factory = SAXParserFactory.newInstance();
//	2.獲得解析器對象
	SAXParser parser = factory.newSAXParser();
//	3.獲得解析器的讀取器
	XMLReader reader = parser.getXMLReader();
//	4.定義讀取器的內容處理器
	reader.setContentHandler(new MyHandler());
//	5.使用讀取器進行解析xml文件
	reader.parse("src/book.xml");

事件處理器:由程序員編寫,通過事件處理器方法的參數就可輕鬆得到sax解析器解析到的數據,從而對數據進行處理(通過事件處理器可以知道sax確實只適合進行讀取操作,不適合CRD)

//	定義處理器類,實現內容處理器接口。如果不想實現過多方法可以繼承一個默認實現類DefaultHandler.只覆蓋想要覆蓋的方法
//	class MyHandler extends DefaultHandler
	class MyHandler implements ContentHandler{
		
//		解析到開始標籤的處理方法
		@Override
		public void startElement(String uri, String localName, String name,
				Attributes atts) throws SAXException {//將該標籤的所有屬性通過Attributes對象傳入
//			直接把開始標籤輸出
			System.out.println("<"+ name + ">");
		}

//		解析到內容的處理方法
		@Override
		public void characters(char[] ch, int start, int length)
				throws SAXException {
//			直接輸出內容
			System.out.println(new String(ch, start, length));
		}
		
//		解析到結束標籤的處理方法
		@Override
		public void endElement(String uri, String localName, String name)
				throws SAXException {
			System.out.println("</"+ name + ">");
		}		}
......實現所有方法}

定義一個想要獲得某個標籤內容的處理器:

//	繼承實現類,覆蓋部分方法
	class GetContentHandler extends DefaultHandler{
//		定義一個變量,獲得當前處理的是哪個標籤
		String currentname = null;
		String needname= "作者";
//		定義想要獲得第幾個標籤的內容
		int neednumber = 2;
		int number = 0;//當前是第幾個該標籤
		
//		需要使用處理開始標籤,結束標籤,內容的方法
		@Override
		public void startElement(String uri, String localName, String qName,
				Attributes attributes) throws SAXException {
			currentname = qName; 
			number++;
		}
		@Override
		public void characters(char[] ch, int start, int length)
				throws SAXException {
//			如果當前是想要的標籤則輸出該內容
			if(currentname.equals(needname) && neednumber==number){
				System.out.println(new String(ch, start, length));
			}
		}
		@Override
		public void endElement(String uri, String localName, String qName)
				throws SAXException {
//			將當前處理的標籤名置爲空,方便下次讀取。如果不清空就會把結束標籤後的換行符也當爲內容來處理,就會影響數據
			currentname = null;
		}
	}
例:結合反射將sax解析的數據封裝到指定的對象中

	class BeanHandler extends DefaultHandler{
		private List list = new ArrayList();
		private String currentname = null;
		private Class clazz;
		private Object bean = null;
		public BeanHandler(Class clazz) {
			super();
			this.clazz = clazz;
		}
		
		@Override
		public void startElement(String uri, String localName, String qName,
				Attributes attributes) throws SAXException {
			currentname = qName;
			if("書".equals(currentname)){
				try {
					bean = clazz.newInstance();
				} catch (Exception e) {
				}
			}
		}
		@Override
		public void characters(char[] ch, int start, int length)
		throws SAXException {
			try {
				Field f = clazz.getDeclaredField(currentname);
				f.setAccessible(true);
				f.set(bean, new String(ch,start,length));
				
			} catch (Exception e) {
				
			}
		}
		@Override
		public void endElement(String uri, String localName, String qName)
		throws SAXException {
			if("書".equals(qName)){
				list.add(bean);
				bean = null;
			}
			currentname = null;
		}

		public List getList() {
			return list;
		}
		
	}

}

}


DOM4j{

是一個簡單、靈活的開源的庫,性能優異,功能強大和極易使用。具體使用方法查看dom4j的快速入門文檔

//		1.創建一個SAX讀取器
		SAXReader reader = new SAXReader();
//		2.通過讀取器直接讀取文件。
		Document document = reader.read(new File("src/book.xml"));
//		3.獲取根節點
		Element root = document.getRootElement();
//		4.獲取根節點的子標籤(有嵌套就需要一層一層的獲得標籤)
			//獲得根節點下的第一個書標籤
		Element book = (Element) root.elements("書").get(1);
//		5.獲得這個書的書名這個標籤的內容及屬性name的值
		String content = book.element("書名").getText();
		String value = book.element("書名").attributeValue("name");
//		爲第一個書的標籤添加一個子標籤
	public void add() throws DocumentException, IOException{
		Document document = new SAXReader().read(new File("src/book.xml"));
//		獲得文檔對象後,獲得根節點再獲得需要添加的標籤
		Element book = document.getRootElement().element("書");
//		爲該標籤添加子標籤並賦值
		book.addElement("售價").setText("50.00元");
		
//		再將內存中的文檔對象寫到xml文件中
			//使用一個文件流來創建將文檔寫到文件的對象xmlwriter
			//亂碼問題:1.設置一個格式輸出器,設置它的編碼,要與xml文檔相同的編碼
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding("UTF-8");
					//  2.如果使用字符流需要指定編碼表,如果使用字節流則不需要(字節流會自己查格式器的碼錶)
//		XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
		XMLWriter writer = new XMLWriter(new OutputStreamWriter(new FileOutputStream("src/book.xml"),"UTF-8"),format);
		writer.write(document);
		writer.close();
	}

//	在指定位置添加一個標籤
		Document document = new SAXReader().read(new File("src/book.xml"));
		Element book = document.getRootElement().element("書");
		List list = book.elements();
//		使用documentHelper來創建標籤,document無該方法
		Element price = DocumentHelper.createElement("售價");
		price.setText("100.00元");
//		將price存到list中的索引爲2的地方(第三個節點),自動將索引爲2或以後的後移
		list.add(2, price);<span style="white-space:pre">		</span>
<span style="white-space:pre">		</span>//更新到xml文件
<span style="white-space:pre">		</span>OutputFormat format = OutputFormat.createPrettyPrint();
<span style="white-space:pre">		</span>format.setEncoding("UTF-8");
<span style="white-space:pre">		</span>XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
<span style="white-space:pre">		</span>writer.write(document);
<span style="white-space:pre">		</span>writer.close();

如果要獲得指定的標籤,結合xpath使用即可:

		SAXReader reader = new SAXReader();
		Document document = reader.read(new File("src/book.xml"));
		List list = document.selectNodes("//作者");//查找多個
		Node node = document.selectSingleNode("//作者");//查找單個
例:
	//xpath應用在查找數據
	public void login(String username, String password) throws DocumentException{
		Document document = new SAXReader().read(new File("src/users.xml"));
//		獲得一個屬性名爲name值爲username並且另一個屬性爲password,值爲password的user標籤
		Node node = document.selectSingleNode("//user[@name='"+username+"'and @password='"+password+"']");
		if(node == null){
			System.out.println("失敗");
		}else{
			System.out.println("成功");
		}
	}


}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章