zoukankan      html  css  js  c++  java
  • WebService(2)-XML系列之用Stax操作Xml

    源代码下载链接: http://pan.baidu.com/s/1ntL1a7R password: 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.写文档和改动文档 


  • 相关阅读:
    7-感觉身体被掏空,但还是要学Pandas(下)
    6-感觉身体被掏空,但还是要学Pandas(上)
    5-Numpy似双丝网,中有千千结(下)
    4-Numpy似双丝网,中有千千结(上)
    3-上帝说要有光,于是就有了Python(下)
    2-上帝说要有光,于是就有了Python(上)
    1-在IPython Notebook中愉快地使用python编程
    第11组 Alpha冲刺(2/6)
    第11组 Alpha冲刺(1/6)
    2019 SDN上机第2次作业
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/6817825.html
Copyright © 2011-2022 走看看