javaweb入門20160305---xml的解析入門

破玉發表於2016-03-05
一個XML檔案除了我們人去讀寫以外,我們希望可以通過程式去讀寫,利用程式去增刪改查XML的過程就是XML程式設計
CRUD:Create、Read、Update、Delete
 
XML兩種解析方式
dom解析
•將整個XML使用類似樹的結構儲存在記憶體中,再對其進行操作。
•是 W3C 組織推薦的處理 XML 的一種方式。
•需要等到XML完全載入進記憶體才可以進行操作
•耗費記憶體,當解析超大的XML時慎用。
•可以方便的對xml進行增刪該查操作
sax解析:(用的多一些)(andrid 中 pull解析類似)
•逐行掃描XML文件,當遇到標籤時觸發解析處理器,採用事件處理的方式解析xml
• (Simple API for XML) 不是官方標準,但它是 XML 社群事實上的標準,幾乎所有的 XML 解析器都支援它。
•在讀取文件的同時即可對xml進行處理,不必等到文件載入結束,相對快捷
•不需要載入進記憶體,因此不存在佔用記憶體的問題,可以解析超大XML
•只能用來讀取XML中資料,無法進行增刪改
 
 
 
SAX解析
SAX採用事件處理的方式解析XML檔案,利用 SAX 解析 XML 文件,涉及兩個部分:解析器和事件處理器。
•SAX解析器可以使用JAXP的API建立,建立出SAX解析器後,就可以指定它去解析某個xml文件。
•SAX每當解析到XML文件的一個組成部分,都會去呼叫事件處理器的一個方法,解析器在呼叫事件處理器的方法時,會把當前解析到的xml檔案內容作為方法的引數傳遞給事件處理器。
•事件處理器由程式設計師編寫,程式設計師通過事件處理器中方法的引數,就可以很輕鬆地得到sax解析器解析到的資料,從而可以決定如何對資料進行處理。
閱讀ContentHandler API文件,常用方法:startElementendElementcharacters
 
SAX方式解析---步驟一
使用SAXParserFactory建立SAX解析工廠
SAXParserFactory spf = SAXParserFactory.newInstance
 
SAX方式解析---步驟二
通過SAX解析工廠得到解析器物件
SAXParser sp = spf.newSAXParser();
 
SAX方式解析---步驟三
通過解析器物件得到一個XML的讀取器
XMLReader xmlReader = sp.getXMLReader();
 
SAX方式解析---步驟四
設定讀取器的事件處理器
xmlReader.setContentHandler(new MyContentHandler());
 
SAX方式解析---步驟五
解析xml檔案
xmlReader.parse("book.xml");
 
 
SAX方式解析ContentHandler
 
void setContentHandler(ContentHandler handler)
ContentHandler是一個介面,我們可以自己寫一個類實現這個介面,其中提供瞭如下重要的方法:
 void characters(char[] ch, int start, int length)
   接收字元資料的通知。
endDocument()
接收文件的結尾的通知。
startDocument()
接收文件的開始的通知。
startElement(String uri, String localName, String qName, Attributes atts)
 接收元素開始的通知。
void endElement(String uri, String localName, String qName)
接收元素結束的通知。
 
 
SAX方式解析DefaultHandler
DefaultHandler是一個類,他預設實現了ContentHandler介面,並提供了其中所有方法的空實現,我們可以自己寫一個類繼承這個類,複寫其中我們需要使用到的方法
 
 
package com.itheima.sax;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;


public class SaxDemo1 {
	public static void main(String[] args) throws Exception {
		//1.獲取解析器工廠
		SAXParserFactory factory = SAXParserFactory.newInstance();
		//2.通過工廠獲取sax解析器
		SAXParser parser = factory.newSAXParser();
		//3.獲取讀取器
		XMLReader reader = parser.getXMLReader();
		//4.註冊事件處理器
		reader.setContentHandler(new MyContentHandler2() );
		//5.解析xml
		reader.parse("book.xml");
		
		
	}
}

//介面卡設計模式
class MyContentHandler2 extends DefaultHandler{
	private String eleName = null;
	private int count = 0;
	@Override
	public void startElement(String uri, String localName, String name,
			Attributes attributes) throws SAXException {
		this.eleName = name;
	}
	
	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		if("書名".equals(eleName) && ++count==2){
			System.out.println(new String(ch,start,length));
		}
	}
	
	@Override
	public void endElement(String uri, String localName, String name)
			throws SAXException {
		eleName = null;
	}
	
}




class MyContentHandler implements ContentHandler{

	public void startDocument() throws SAXException {
		System.out.println("文件解析開始了.......");
	}
	
	public void startElement(String uri, String localName, String name,
			Attributes atts) throws SAXException {
		System.out.println("發現了開始標籤,"+name);
	}
	
	public void characters(char[] ch, int start, int length)
		throws SAXException {
		System.out.println(new String(ch,start,length));
	}
	
	public void endElement(String uri, String localName, String name)
		throws SAXException {
		System.out.println("發現結束標籤,"+name);
	}

	
	public void endDocument() throws SAXException {
		System.out.println("文件解析結束了.......");
	}
	
	
	
	
	
	
	
	
	
	public void endPrefixMapping(String prefix) throws SAXException {
		// TODO Auto-generated method stub
		
	}

	public void ignorableWhitespace(char[] ch, int start, int length)
			throws SAXException {
		// TODO Auto-generated method stub
		
	}

	public void processingInstruction(String target, String data)
			throws SAXException {
		// TODO Auto-generated method stub
		
	}

	public void setDocumentLocator(Locator locator) {
		// TODO Auto-generated method stub
		
	}

	public void skippedEntity(String name) throws SAXException {
		// TODO Auto-generated method stub
		
	}

	

	

	public void startPrefixMapping(String prefix, String uri)
			throws SAXException {
		// TODO Auto-generated method stub
		
	}
	
}

  

DOM4J解析
DOM4J解析XML文件
 
Dom4j是一個簡單、靈活的開放原始碼的庫。Dom4j是由早期開發JDOM的人分離出來而後獨立開發的。與JDOM不同的是,dom4j使用介面和抽象基類,雖然Dom4j的API相對要複雜一些,但它提供了比JDOM更好的靈活性。
Dom4j是一個非常優秀的Java XML API,具有效能優異、功能強大和極易使 用的特點。現在很多軟體採用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。
使用Dom4j開發,需下載dom4j相應的jar檔案。
 
建立解析器:
SAXReader reader = new SAXReader();
利用解析器讀入xml文件:
Document   document = reader.read(new File("input.xml"));
獲取文件的根節點:
 Element root = document.getRootElement();
 
1.取得某個節點的子節點.
Element element =ele.element(“書名");
List elementList =ele.elements(“書名");
List elementList =ele.elements();
 
2.獲取節點的名字
node.getName();
 
3.設定節點的名字
node.setName(String newName);
 
4.取得節點的文字(標籤體)
String text=node.getText()
5.設定節點的文字(標籤體)
node.setText("aaa");
 
6.新增子節點.
ele.add(Element e);
ele.addElement("age");
 
7.刪除子節點節點.
parentElm.remove(childElm);
 
8獲取節點型別
node.getNodeType() ;
 
9.獲取父節點
node.getParent();
 
10.取得某節點物件的某屬性
Attribute attr= ele.attribute("aaa");
Attribute attr= ele.attribute(0);
List list = ele.attributes();
String value = ele.attributeValue("aaa");
Iterator it = ele.attributeIterator();
 
11.設定某節點的屬性
ele.add(Attribute attr);
ele.addAttribute(name, value);
ele.setAttributes(List attrs);
 
12.刪除某屬性
 ele.remove(attribute);
13.在指定位置插入節點
•1.得到插入位置的節點列表(list)
•2.呼叫list.add(index,elemnent),由index決定element的插入位置。
•Element元素可以通過DocumentHelper物件得到。示例程式碼:
 
Element aaa = DocumentHelper.createElement("aaa");
aaa.setText("aaa");
 
List list = root.element("").elements();
list.add(1, aaa);
 
 
DOM4j屬性
1.取得屬性的名、值
String name = attribute.getName();
String value = attribute.getValue();
 
2.設定某屬性的名、值
attribute.setName();
attribute.setValue();
 
DOM4j字串和XML的轉換
1.將字串轉化為XML
 
     String text = "<members> <member>sitinspring</member></members>";
Document document = DocumentHelper.parseText(text);
 
2.將文件或節點的XML轉化為字串.
String xmlStr = node.asXML();
 
DOM4j將文件寫入XML檔案
方式一:
呼叫Node提供的write(Writer writer) 方法,使用預設方式將節點輸出到流中:
node.write(new FileWriter("book.xml"));
•亂碼問題:Dom4j在將文件載入記憶體時使用的是文件宣告中encoding屬性宣告的編碼集進行編碼,如果在此時使用的writer的內部編碼集與最初載入記憶體時使用的編碼集不同則會出現亂碼問題。
•FileWriter預設使用作業系統本地碼錶即gb2312編碼,並且無法更改。
•此時可以使用OutputStreamWriter(FileOutputStream("filePath"),"utf-8");的方式自己封裝一個指定碼錶的Writer使用,從而解決亂碼問題。
 
l方式二:
利用XMLWriter寫出Node:
  XMLWriter writer = new XMLWriter(new  FileWriter("output.xml"));
  writer.write(node);
  writer.close();
•注意:使用這種方式輸出時,XMLWriter首先會將記憶體中的docuemnt翻譯成UTF-8格式的document,在進行輸出,這時有可能出現亂碼問題。
•可以使用OutputFormat 指定XMLWriter轉換的編碼為其他編碼。
OutputFormat format = OutputFormat.createPrettyPrint();            
     format.setEncoding("GBK");       
XMLWriter writer =
new XMLWriter(newFileWriter("output.xml"),format);
•Writer使用的編碼集與文件載入記憶體時使用的編碼集不同導致亂碼,使用位元組流或自己封裝指定編碼的字元流即可。參照上文
 
 
 
 
 

你所應該知道的Dom4J

建立解析器:

SAXReader reader = new SAXReader();

利用解析器讀入xml文件:
Document   document = reader.read(new File("input.xml"));

獲取文件的根節點:

Element root = document.getRootElement();

介面繼承結構:

Node  ---

Branch

--Document

--Element

----

Attribute

 

Node介面

String

asXML()
asXMLreturns the textual XML representation of this node.

將一個節點轉換為字串

String

getName()
getNamereturns the name of this node.

獲取節點的名稱,如果是元素則獲取到元素名,如果是屬性獲取到屬性名

short

getNodeType()
Returns the code according to the type of node.

獲取節點型別,Node介面上定義了一些靜態short型別的常量用來表示各種型別

Element

getParent()
getParentreturns the parent Element if this node supports the parent relationship or null if it is the root element or does not support the parent relationship.

獲取父節點,如果是根元素呼叫則返回null,如果是其他元素呼叫則返回父元素,如果是屬性呼叫則返回屬性所依附的元素。

String

getText()
Returns the text of this node.

返回節點文字,如果是元素則返回標籤體,如果是屬性則返回屬性值

List

selectNodes(String xpathExpression)
selectNodesevaluates an XPath expression and returns the result as a List of Node instances or String instances depending on the XPath expression.

利用xpath表示式,選擇節點

void

setName(String name)
Sets the text data of this node or this method will throw an UnsupportedOperationException if it is read-only.

設定節點的名稱,元素可以更改名稱,屬性則不可以,會丟擲UnsupportedOperationException 異常

void

setText(String text)
Sets the text data of this node or this method will throw an UnsupportedOperationException if it is read-only.

設定節點內容,如果是元素則設定標籤體,如果是屬性則設定屬性的值

void

write(Writer writer)
writewrites this node as the default XML notation for this node.

將節點寫出到一個輸出流中,元素、屬性均支援

 

 

Branch介面(實現了Node介面

void

add(Element element)
Adds the given Element to this branch.

增加一個子節點

Element

addElement(QName qname)
Adds a new Element node with the given QNameto this branch and returns a reference to the new node.

增加一個給定名字的子節點,並且返回這個新建立的節點的引用

int

indexOf(Node node)
Returns the index of the given node if it is a child node of this branch or -1 if the given node is not a child node.

獲取給定節點在所有直接點中的位置號,如果該節點不是此分支的子節點,則返回-1

boolean

remove(Element element)
Removes the given Element if the node is an immediate child of this branch.

刪除給定子元素,返回布林值表明是否刪除成功。

 

Element介面(實現了BranchNode介面)

void

add(Attribute attribute)
Adds the given Attribute to this element.

增加一個屬性

Element

addAttribute(QName qName, String value)
Adds the attribute value of the given fully qualified name.

為元素增加屬性,用給定的屬性名和屬性值,並返回該元素

Element 

addAttribute(String name, String value)
           Adds the attribute value of the given local name. 

為元素增加屬性

Attribute

attribute(int index)
Returns the attribute at the specified indexGets the

獲取指定位置的屬性

Attribute

attribute(QName qName)
DOCUMENT ME!

獲取指定名稱的屬性

Iterator

attributeIterator()
DOCUMENT ME!

獲取屬性迭代器

List

attributes()
Returns the Attributeinstances this element contains as a backed Listso that the attributes may be modified directly using the Listinterface.

獲取該元素的所有屬性,以一個list返回

String

attributeValue(QName qName)
This returns the attribute value for the attribute with the given fully qualified name or null if there is no such attribute or the empty string if the attribute value is empty.

獲取指定名稱屬性的值,如果不存在該屬性返回null,如果存在該屬性但是屬性值為空,則返回空字串

Element

element(QName qName)
Returns the first element for the given fully qualified name.

獲取指定名稱的子元素,如果有多個該名稱的子元素,則返回第一個

Element

element(String name)
Returns the first element for the given fully qualified name.

獲取指定名稱的子元素,如果有多個該名稱的子元素,則返回第一個

Iterator

elementIterator()
Returns an iterator over all this elements child elements.

獲取子元素迭代器

Iterator

elementIterator(QName qName)
Returns an iterator over the elements contained in this element which match the given fully qualified name.

獲取指定名稱的子元素的迭代器

List

elements()
Returns the elements contained in this element.

獲取所有子元素,並用一個list返回

List

elements(QName qName)
Returns the elements contained in this element with the given fully qualified name.

獲取所有指定名稱的子元素,並用一個list返回

String

getText()
Returns the text value of this element without recursing through child elements.

獲取元素標籤體

boolean

remove(Attribute attribute)
Removes the given Attribute from this element.

移除元素上的屬性

void

setAttributes(List attributes)
Sets the attributes that this element contains

將list中的所有屬性設定到該元素上

 

Attribute介面(實現了Node介面)

QName

getQName()
Returns the QName of this attribute which represents the local name, the qualified name and the Namespace.

獲取屬性名稱

String

getValue()
Returns the value of the attribute.

獲取屬性的值

void

setValue(String value)
Sets the value of this attribute or this method will throw an UnsupportedOperationException if it is read-only.

設定屬性的值

 

 

DocumentHelper 

static Attribute

createAttribute(Element owner, QName qname, String value)

建立一個Attribute

static Document

createDocument()

建立一個Document

static Document

createDocument(Element rootElement)

以給定元素作為根元素建立Document

 

static Element

createElement(QName qname)

以給定名稱建立一個Element

static Document

parseText(String text)
parseTextparses the given text as an XML document and returns the newly created Document.

將一段字串轉化為Document

 

 

將節點寫出到XML檔案中去

方法1

呼叫Node提供的write(Writer writer) 方法,使用預設方式將節點輸出到流中:

node.write(new FileWriter("book.xml"));

亂碼問題:

Dom4j在將文件載入記憶體時使用的是文件宣告中encoding屬性宣告的編碼集進行編碼, 如果在此時使用writer輸出時writer使用的內部編碼集與encoding不同則會有亂碼問題。

FileWriter預設使用作業系統本地碼錶即gb2312編碼,並且無法更改。

此時可以使用OutputStreamWriter(FileOutputStream("filePath"),"utf-8");的方式自己封裝 一個指定碼錶的Writer使用,從而解決亂碼問題。

方式2:

利用XMLWriter寫出Node:
   XMLWriter writer = new XMLWriter(new  FileWriter("output.xml"));
   writer.write(node);
  writer.close();

亂碼問題:

1)使用這種方式輸出時,XMLWriter首先會將記憶體中的docuemnt翻譯成UTF-8 格式的document,在進行輸出,這時有可能出現亂碼問題。

可以使用OutputFormat 指定XMLWriter轉換的編碼為其他編碼。

OutputFormat format = OutputFormat.createPrettyPrint();             

    format.setEncoding("GBK");       
XMLWriter writer = new XMLWriter(new FileWriter("output.xml"),format);

2Writer使用的編碼集與文件載入記憶體時使用的編碼集不同導致亂碼,使用位元組流 或自己封裝指定編碼的字元流即可(參照方法1)。

 

package com.itheima.dom4j;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class Dom4jDemo1 {
	public static void main(String[] args) throws Exception {
		//1.獲取解析器
		SAXReader reader = new SAXReader();
		//2.解析xml獲取代表整個文件的dom物件
		Document dom = reader.read("book.xml");
		//3.獲取根節點
		Element root = dom.getRootElement();
		//4.獲取書名進行列印
		String bookName = root.element("書").element("書名").getText();
		System.out.println(bookName);
	}
}

 

  

package com.itheima.dom4j;

import java.io.FileOutputStream;
import java.util.List;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.junit.Test;

public class Demo4jDemo2 {
	@Test
	public void attr() throws Exception{
		SAXReader reader = new SAXReader();
		Document dom = reader.read("book.xml");
		Element root = dom.getRootElement();
		
		Element bookEle = root.element("書");
		//bookEle.addAttribute("出版社", "傳智出版社");
//		String str = bookEle.attributeValue("出版社");
//		System.out.println(str);
		Attribute attr = bookEle.attribute("出版社");
		attr.getParent().remove(attr);
		
		XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
		writer.write(dom);
		writer.close();
	}
	
	@Test
	public void del() throws Exception{
		SAXReader reader = new SAXReader();
		Document dom = reader.read("book.xml");
		Element root = dom.getRootElement();
		
		Element price2Ele = root.element("書").element("特價");
		price2Ele.getParent().remove(price2Ele);

		XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
		writer.write(dom);
		writer.close();
	}
	
	@Test
	public void update()throws Exception{
		SAXReader reader = new SAXReader();
		Document dom = reader.read("book.xml");
		Element root = dom.getRootElement();
		
		root.element("書").element("特價").setText("4.0元");
		
		XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
		writer.write(dom);
		writer.close();
	}
	
	@Test
	public void add()throws Exception{
		SAXReader reader = new SAXReader();
		Document dom = reader.read("book.xml");
		Element root = dom.getRootElement();
		//憑空建立<特價>節點,設定標籤體
		Element price2Ele = DocumentHelper.createElement("特價");
		price2Ele.setText("40.0元");
		//獲取父標籤<書>將特價節點掛載上去
		Element bookEle = root.element("書");
		bookEle.add(price2Ele);
		
		//將記憶體中的dom樹會寫到xml檔案中,從而使xml中的資料進行更新
//		FileWriter writer = new FileWriter("book.xml");
//		dom.write(writer);
//		writer.flush();
//		writer.close();
		XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
		writer.write(dom);
		writer.close();
	}
	
	@Test
	public void find() throws Exception{
		SAXReader reader = new SAXReader();
		Document dom = reader.read("book.xml");
		Element root = dom.getRootElement();
		
		List<Element> list =  root.elements();
		Element book2Ele = list.get(1);
		System.out.println(book2Ele.element("書名").getText());
		
	}
}

  

 

 
 
 
 
 
 
 

相關文章