源碼下載:鏈接: http://pan.baidu.com/s/1ntL1a7R 密碼: rwp1
本文主要講述:利用Stax處理xml文檔
一.讀取xml
1.基於光標的查找
核心:XMLInputFactory,XMLStreamReader
好處:效率最高
壞處:但是操作不方便
TestStax_readElement.java
package com.tgb.stax.v1_cursor;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.junit.Test;
/**
* 通過光標方式讀取XML文件-讀取開始節點START_ELEMENT、結束節點END_ELEMENT、文本節點CHARACTERS
* @author 趙慄婧
* @version 1.0.0 , 2015年6月25日 下午12:12:55
*/
public class TestStax_readElement {
//通過XMLInputFactory,讀取xml文件中的:開始元素、內容、結束元素
@Test
public void testReadElement() {
XMLInputFactory factory = XMLInputFactory.newInstance();
InputStream is = null;
try {
//以下是讀取路徑文件的兩種方式(注意此處的路徑問題!):
is=TestStax_readElement.class.getClassLoader().getResourceAsStream("com/tgb/stax/v1_cursor/books.xml");
//is = TestStax.class.getClassLoader().getResourceAsStream("com\\tgb\\stax\\v1_cursor\\books.xml");
System.out.println("IS:" + is);
XMLStreamReader reader = factory.createXMLStreamReader(is);
// 範例解析:
// type:1 START_ELEMENT:title
// type:4 CHARACTERS:Everyday Italian
// type:2 END_ELEMENT:/title
while (reader.hasNext()) {
int type = reader.next();
// 打印出:節點類型
System.out.println("type:" + type);
//如果是:開始元素節點,則打印
if (type == XMLStreamConstants.START_ELEMENT) {
System.out.println("START_ELEMENT:" + reader.getName().toString());
} else if (type == XMLStreamConstants.CHARACTERS) {
//如果是文本節點,則打印
System.out.println(" CHARACTERS:" + reader.getText().trim());
} else if (type == XMLStreamConstants.END_ELEMENT) {
//如果是結束元素節點,則打印
System.out.println("END_ELEMENT:/" + reader.getName());
}
}
} catch (FactoryConfigurationError e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
} finally {
//如果輸入流InputStream不爲空,則手動關閉
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
TestStax_readElementText.java
package com.tgb.stax.v1_cursor;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.junit.Test;
/**
* 通過光標方式讀取XML文件-根據START_ELEMEN的名稱,讀取ElementText
* @author 趙慄婧
* @version 1.0.0 , 2015年6月25日 下午12:12:55
*/
public class TestStax_readElementText {
//測試:讀取屬性、屬性對應的值
@Test
public void testReadElementText(){
XMLInputFactory factory =XMLInputFactory.newInstance();
InputStream is =null;
try {
is=TestStax_readElementText.class.getClassLoader().getResourceAsStream("com/tgb/stax/v1_cursor/books.xml");
XMLStreamReader reader = factory.createXMLStreamReader(is);
//範例:讀取ElementText
//讀取:<title lang="en">Everyday Italian</title>
// <price>30.00</price>
//根據title,讀取Everyday Italian
//根據price讀取:30.00
while (reader.hasNext()) {
int type = reader.next();
if (type==XMLStreamConstants.START_ELEMENT) {
String name = reader.getName().toString();
if ("title".equals(name)) {
System.out.println("title:"+reader.getElementText());
}
if ("price".equals(name)) {
System.out.println("price:"+reader.getElementText());
}
}
}
} catch (FactoryConfigurationError | XMLStreamException e) {
e.printStackTrace();
}finally{
try {
if (is!=null) is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
TestStax_readAttributeValue.java
package com.tgb.stax.v1_cursor;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.junit.Test;
/**
* 通過光標方式讀取XML文件-根據START_ELEMEN的名稱,讀取Attribute和Value
* @author 趙慄婧
* @version 1.0.0 , 2015年6月25日 下午12:12:55
*/
public class TestStax_readAttributeValue {
//測試:讀取屬性、屬性對應的值
@Test
public void testReadAttributeValue(){
XMLInputFactory factory =XMLInputFactory.newInstance();
InputStream is =null;
try {
is=TestStax_readAttributeValue.class.getClassLoader().getResourceAsStream("com/tgb/stax/v1_cursor/books.xml");
XMLStreamReader reader = factory.createXMLStreamReader(is);
//範例:
//讀取:<book category="COOKING">中,START_ELEMENT=book的相應信息
//結果爲:category,COOKING
while (reader.hasNext()) {
int type = reader.next();
if (type==XMLStreamConstants.START_ELEMENT) {
String name = reader.getName().toString();
if(name.equals("book")){
System.out.println(reader.getAttributeName(0)+","+reader.getAttributeValue(0));
}
}
}
} catch (FactoryConfigurationError | XMLStreamException e) {
e.printStackTrace();
}finally{
try {
if (is!=null) is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.基於迭代器模型的查找
通過XMLEventReader,根據開始節點名稱START_ELEMENT,獲取對應的ElementText值
TestStax_iterator.java
package com.tgb.stax.v2_iterator;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.XMLEvent;
import org.junit.Test;
/**
* 採用迭代器的方式操作XML文檔
* @author 趙慄婧
* @version 1.0.0 , 2015年6月25日 下午12:11:47
*/
public class TestStax_iterator {
//通過XMLEventReader,根據開始節點名稱START_ELEMENT,獲取對應的ElementText值
@Test
public void testReadElement() {
XMLInputFactory factory = XMLInputFactory.newInstance();
InputStream is = null;
try {
//以下是讀取路徑文件的兩種方式(注意此處的路徑問題!):
is=TestStax_iterator.class.getClassLoader().getResourceAsStream("com/tgb/stax/v2_iterator/books.xml");
//is = TestStax.class.getClassLoader().getResourceAsStream("com\\tgb\\stax\\v2_iterator\\books.xml");
//基於迭代模型的操作方式
XMLEventReader reader = factory.createXMLEventReader(is);
int num =0;
while (reader.hasNext()){
//通過XMLEvent來獲取是否是某種節點類型
XMLEvent event = reader.nextEvent();
//判斷是否爲:開始節點:START_ELEMENT
if (event.isStartElement()) {
//通過event.as***轉化爲節點
String name =event.asStartElement().getName().toString();
if ("title".equals(name)) {
System.out.println("ElementText:"+reader.getElementText());
}
}
num++;
}
//結果是93條
System.out.println("num:"+num);
} catch (FactoryConfigurationError e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
} finally {
//如果輸入流InputStream不爲空,則手動關閉
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3.基於過濾器
點評:基於光標/迭代器,都是建立在遍歷整個文檔的基礎之上。
過濾器,過濾掉了我們不需要的文檔
* 採用過濾器的方式操作XML文件
* 若在XMLEventReader的構造函數中,不使用過濾,則需要循環num=25次
* 若在XMLEventReader的構造函數中,使用title和price過濾,則需要循環num=8次,效率更高
* 而v2_iterator迭代器的方式,效率更低num=93
TestStax_filter.java
package com.tgb.stax.v3_filter;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.stream.EventFilter;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.XMLEvent;
import org.junit.Test;
/**
* 採用過濾器的方式操作XML文件
* 若在XMLEventReader的構造函數中,不使用過濾,則需要循環num=25次
* 若在XMLEventReader的構造函數中,使用title和price過濾,則需要循環num=8次,效率更高
* 而v2_iterator迭代器的方式,效率更低num=93
* @author 趙慄婧
* @version 1.0.0 , 2015年6月25日 下午12:04:28
*/
public class TestStax_filter {
//通過XMLEventReader,根據開始節點名稱START_ELEMENT,獲取對應的ElementText值
@Test
public void testReadElement() {
XMLInputFactory factory = XMLInputFactory.newInstance();
InputStream is = null;
try {
//以下是讀取路徑文件的兩種方式(注意此處的路徑問題!):
is=TestStax_filter.class.getClassLoader().getResourceAsStream("com/tgb/stax/v3_filter/books.xml");
//is = TestStax.class.getClassLoader().getResourceAsStream("com\\tgb\\stax\\v3_filter\\books.xml");
//基於Filter的過濾方式,可以有效過濾刁不用進行操作的節點,效率更高一些。
XMLEventReader reader = factory.createFilteredReader(factory.createXMLEventReader(is),
new EventFilter() {
@Override
public boolean accept(XMLEvent event) {
//返回true表示顯示;返回false表示不顯示
//開始:通過此處過濾以後,效率大幅度提高,num=8
if (event.isStartElement()) {
String name = event.asStartElement().getName().toString();
if ("title".equals(name)||"price".equals(name)) {
return true;
}
}
//結束:通過此處過濾以後,效率大幅度提高,num=8
return false;
}
});
int num = 0 ;
while (reader.hasNext()){
//通過XMLEvent來獲取是否是某種節點類型
XMLEvent event = reader.nextEvent();
//判斷是否爲:開始節點:START_ELEMENT
if (event.isStartElement()) {
//通過event.as***轉化爲節點
String name =event.asStartElement().getName().toString();
if ("title".equals(name)) {
System.out.print("title:"+reader.getElementText()+"-------->");
}else if ("price".equals(name)) {
System.out.println("price:"+reader.getElementText());
}
}
num++;
}
//此處結果是25條
//若在XMLEventReader的構造函數中,使用title和price過濾,則num=8,效率更高
System.out.println("num:"+num);
} catch (FactoryConfigurationError e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
} finally {
//如果輸入流InputStream不爲空,則手動關閉
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
4.基於xpath的處理
此處採用xpath方式操作XML文檔。(需要把xml文檔【Document】讀進來)
* 效率不高
* 不一定加載全部文檔源,可以截取的
好處:獲取節點最好的方式
缺點:需要加載整個文檔
TestStax_xpath.java
package com.tgb.stax.v4_xpath;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.XMLEvent;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* 此處採用xpath方式操作XML文檔。(需要把xml文檔【Document】讀進來)
* 效率不高
* 不一定加載全部文檔源,可以截取的
* @author 趙慄婧
* @version 1.0.0 , 2015年6月25日 下午12:10:48
*/
public class TestStax_xpath {
//通過XMLEventReader,根據開始節點名稱START_ELEMENT,獲取對應的ElementText值
@Test
public void testReadElement() {
XMLInputFactory factory = XMLInputFactory.newInstance();
InputStream is = null;
int num=0;
//以下是讀取路徑文件的兩種方式(注意此處的路徑問題!):
is=TestStax_xpath.class.getClassLoader().getResourceAsStream("com/tgb/stax/v4_xpath/books.xml");
//is = TestStax.class.getClassLoader().getResourceAsStream("com\\tgb\\stax\\v4_path\\books.xml");
//基於迭代模型的操作方式
try {
//先創建文檔處理對象DocumentBuilder
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
//通過DocumentBuilder創建Document文檔對象
Document document = db.parse(is);
//創建XPath對象
XPath xPath=XPathFactory.newInstance().newXPath();
//第一個參數就是xpath,第二個參數就是文檔,第三個參數是常數節點集
NodeList list =(NodeList)xPath.evaluate("//book[@category='WEB']", document,XPathConstants.NODESET);
//遍歷輸出相應結果
for(int i=0;i<list.getLength();i++){
Element e = (Element) list.item(i);
System.out.print(e.getElementsByTagName("title").item(0).getTextContent());
System.out.print(":");
System.out.println(e.getElementsByTagName("price").item(0).getTextContent());
num++;
}
System.out.println("num:"+num);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (XPathExpressionException e) {
e.printStackTrace();
}finally{
//關閉輸入流
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
二.寫文檔和修改文檔
使用XMLStreamWriter創建XML
package com.tgb.stax.v5_writeandeditxml;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.stream.events.XMLEvent;
import org.junit.Test;
/**
* 利用XMLStreamWriter 代碼中寫一個XML文件
* @author 趙慄婧
* @version 1.0.0 , 2015年6月26日 上午10:32:52
*/
public class TestStax_writexml {
@Test
public void testReadElement() {
try {
//注意順序
System.out.println("---Demo:第一個(沒有命名空間)-------------------------------------------");
//第一個,結果
//<?xml version="1.0" encoding="UTF-8"?>
//<people>
// <id>
// 1070541038
// </id>
//</people>
XMLStreamWriter xsw = XMLOutputFactory.newInstance().createXMLStreamWriter(System.out);
xsw.writeStartDocument("UTF-8","1.0");
xsw.writeEndDocument();
xsw.writeStartElement("people");
xsw.writeStartElement("id");
xsw.writeCharacters("1070541038");
xsw.writeEndElement();
xsw.writeEndElement();
xsw.flush();//清空
xsw.close();//關閉
System.out.println();
System.out.println("---Demo:第二個(添加命名空間)-------------------------------------------");
//Demo:第二個(添加命名空間),結果
//<?xml version="1.0" encoding="UTF-8"?>
//<namespace_lizi:person>
// <namespace_lizi:id>
// 1070541038
// </namespace_lizi:id>
//</namespace_lizi:person>
XMLStreamWriter xsw2 = XMLOutputFactory.newInstance().createXMLStreamWriter(System.out);
xsw2.writeStartDocument("UTF-8","1.0");
xsw2.writeEndDocument();
String prefix ="namespace_lizi";
String localName1 = "person";
String localName2 = "id";
String namespaceURI ="ns";
xsw2.writeStartElement(prefix, localName1, namespaceURI);
xsw2.writeStartElement(namespaceURI, localName2);
xsw2.writeCharacters("1070541038");
xsw2.writeEndElement();
xsw2.writeEndElement();
xsw2.flush();
xsw2.close();
} catch (XMLStreamException e) {
e.printStackTrace();
} catch (FactoryConfigurationError e) {
e.printStackTrace();
}
}
}
使用Transformer更新節點信息
package com.tgb.stax.v5_writeandeditxml;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.xml.crypto.dsig.Transform;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
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 javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* 利用Transformer修改XML中節點信息
* @author 趙慄婧
* @version 1.0.0 , 2015年6月26日 上午10:33:21
*/
public class TestStax_editxml {
//描述:修改節點中的值
@Test
public void testeditxml() {
InputStream is = null;
try {
//讀取路徑文件
is = TestStax_editxml.class.getResourceAsStream("books.xml");
//先創建文檔處理對象
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
//通過文檔處理對象,創建文檔對象
Document document = db.parse(is);
//創建XPath對象
XPath xpath = XPathFactory.newInstance().newXPath();
//創建Transformer對象
Transformer transformer = TransformerFactory.newInstance().newTransformer();
//設置輸出屬性的編碼格式:UTF-8
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
//設置輸出屬性的第一個元素<bookstore>,換行
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//第一個參數就是xpath,第二個參數就是文檔,第三個參數是常數節點集
//NodeList list =(NodeList)xPath.evaluate("//book[@category='WEB']", document,XPathConstants.NODESET);
NodeList list = (NodeList)xpath.evaluate("//book[title='Learning XML']", document,XPathConstants.NODESET);
//獲取第一個book元素
Element bookElement = (Element)list.item(0);
//獲取book元素中的第一個price元素
Element element =(Element)(bookElement.getElementsByTagName("price").item(0));
//把課本的price屬性設置價格爲5000元
element.setTextContent("5000");
//創建結果對象
Result result = new StreamResult(System.out);
//通過transformer修改節點。將變化後的結果,輸出
transformer.transform(new DOMSource(document), result);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerFactoryConfigurationError e) {
e.printStackTrace();
} catch (XPathExpressionException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}finally{
//關閉輸入流
if (is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
三.總結
本文主要講述了通過stax操作XML文件。
1.讀取xml 的4種方式:
1).基於光標的查找
2).基於迭代器模型的查找
3).基於過濾器
4).基於xpath的處理
點評:基於光標/迭代器,都是建立在遍歷整個文檔的基礎之上。
過濾器,過濾掉了我們不需要的內容,效率更高。
xpath方式,需要把xml文檔都讀進來(可以截取),效率不高
2.寫文檔和修改文檔