2014-06-30 Web中XML的学习(2)-----XML文档Java语言解析

1.XML解析技术概述

XML现在已经成为一种通用的数据交换格式,它的平台无关性,语言无关性,系统无关性,给数据集成与交互带来了极大的方便。

XML解析方式分为两种:dom和sax
    dom:(Document Object Model, 即文档对象模型) 是 W3C 组织推荐的处理 XML 的一种方式。
    sax: (Simple API for XML) 不是官方标准,但它是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。
XML解析器
    Crimson、Xerces 、Aelfred2
XML解析开发包
    Jaxp、Jdom、dom4j

2.JAXP实现DOM解析

JAXP 开发包是J2SE的一部分,它由javax.xml、org.w3c.dom 、org.xml.sax 包及其子包组成,在javax.xml.parsers 包中,定义了几个工厂类,程序员调用这些工厂类,可以得到对xml文档进行解析的 DOM 或 SAX 的解析器对象。

  • 代码实现:

package com.itheima.dom.jdk;
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.w3c.dom.Document;
public class JdkDomParserUtil {
	/**
	 * 将XML文件转化为Document对象到内存
	 * @param path
	 * @return document
	 * @throws Exception
	 */
	public static Document getDocument(String path) throws Exception{
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder=factory.newDocumentBuilder();
		Document document = builder.parse(path);
		return document;
	}
	/**
	 * 将内存中Document写入文件
	 * @param document
	 * @param path
	 * @throws Exception
	 */
	public static void writeDocument2Xml(Document document,String path) throws Exception {
		Transformer transformer=TransformerFactory.newInstance().newTransformer();
		transformer.transform(new DOMSource(document), new StreamResult(path));
	}
}

  • 实现操作代码:

package com.itheima.dom.jdk;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class JdkDomParser {
	/**
	 * 获取文档节点中第二个书中作者的文本内容
	 * @param document
	 * @return Node
	 * @throws Exception 
	 */
	public static String findXmlInfo(String path) throws Exception{
		Document document=JdkDomParserUtil.getDocument(path);
		NodeList nodes=document.getElementsByTagName("作者");
		Node node=nodes.item(1);
		return node.getFirstChild().getNodeValue();
	}
	/**
	 *  在第二个书中添加一个节点,如:
	 * <市场价>5000</市场价>
	 * @param document
	 * @throws Exception 
	 */
	public static void addNode2Xml(String path) throws Exception{
		Document document=JdkDomParserUtil.getDocument(path);
		Element element=document.createElement("市场价");
		element.setTextContent("5000");
		Element elementParent=(Element) document.getElementsByTagName("书").item(1);
		elementParent.appendChild(element);
		JdkDomParserUtil.writeDocument2Xml(document, path);
	}
	/**
	 * 将第二本书<市场价>5000</市场价>修改成<批发价格>300</批发价格>
	 * @throws Exception 
	 */
	public static void modifyNode2Xml(String path) throws Exception{
		Document document=JdkDomParserUtil.getDocument(path);
		Element newElement=document.createElement("批发价格");
		newElement.setTextContent("300");
		Element olderElement = (Element) document.getElementsByTagName("市场价").item(0);
		document.getElementsByTagName("书").item(1).replaceChild(newElement, olderElement);
		JdkDomParserUtil.writeDocument2Xml(document, path);
	}
	/**
	 * 将第二本书<批发价格>300</批发价格>节点删除
	 * @throws Exception 
	 */
	public static void deleteNode2Xml(String path) throws Exception{
		Document document=JdkDomParserUtil.getDocument(path);
		Element element = (Element) document.getElementsByTagName("批发价格").item(0);
		document.getElementsByTagName("书").item(1).removeChild(element);
		JdkDomParserUtil.writeDocument2Xml(document, path);
	}
}

  • 实验数据:books.xml

<?xml version="1.0" encoding="UTF-8"?>
<书架>
	<书>
		<书名>葵花宝典</书名>
		<作者>宋美成</作者>
		<售价>200</售价>
	</书>
	<书>
		<书名>菊花宝典</书名>
		<作者>黑马程序员</作者>
		<售价>400</售价>
	</书>
	<书>
		<书名>菜花宝典</书名>
		<作者>宋美成3</作者>
		<售价>800</售价>
	</书>
</书架>

  • 测试代码:

package com.itheima.junit;
import org.junit.Test;
import com.itheima.dom.jdk.JdkDomParser;
public class DomParserJDKTest {
	private static String path="src//books.xml";
	@Test
	public void testFindDocumentInfo() {
		try {
			String info=JdkDomParser.findXmlInfo(path);
			System.out.println(info);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	@Test
	public void testAddNode2Document() {
		try {
			JdkDomParser.addNode2Xml(path);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	@Test
	public void testModifyNode2Xml(){
		try {
			JdkDomParser.modifyNode2Xml(path);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	@Test 
	public void testDeleteNode2Xml(){
		try {
			JdkDomParser.deleteNode2Xml(path);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

  测试结果省略......

3.JAXP实现Sax解析

核心代码:
    使用SAXParserFactory创建SAX解析工厂
    SAXParserFactory spf = SAXParserFactory.newInstance();
    通过SAX解析工厂得到解析器对象  
    SAXParser sp = spf.newSAXParser();
    通过解析器对象得到一个XML的读取器
    XMLReader xmlReader = sp.getXMLReader();
    设置读取器的事件处理器  
    xmlReader.setContentHandler(new BookParserHandler());

  • 通过Sax解析XML文档,然后将数据填充到相对应的JavaBean中.

package com.itheima.sax;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import com.itheima.domain.Book;
public class SaxParserTest2 {
	public static void main(String[] args) throws Exception {
		SAXParser parser=SAXParserFactory.newInstance().newSAXParser();
		XMLReader reader=parser.getXMLReader();
		final List<Book> books = new ArrayList<Book>();
		reader.setContentHandler(new DefaultHandler(){
			Book book = null;
			String name = null;   //记住不同的标签 
			public void startElement(String uri, String localName,
					String qName, Attributes attributes) throws SAXException {
				if("书".equals(qName)){
					book = new Book();
				}
				name = qName;
			}
			public void endElement(String uri, String localName, String qName)
					throws SAXException {
				if("书".equals(qName)){
					books.add(book);
				}
				name = null;
			}
			public void characters(char[] ch, int start, int length)
					throws SAXException {
				if("书名".equalsIgnoreCase(name)){
					book.setName(new String(ch,start,length));
				}
				if("作者".equalsIgnoreCase(name)){
					book.setAuthor(new String(ch,start,length));
				}
				if("售价".equalsIgnoreCase(name)){
					book.setPrice(Double.parseDouble(new String(ch,start,length)));
				}
			}
		});
		reader.parse("src//books.xml");
		for(Book b:books){
			System.out.println(b);
		}
	}
}

2014-06-30 Web中XML的学习(2)-----XML文档Java语言解析_第1张图片


4.Dom4j解析XML文档

虽然DOM4J代表了完全独立的开发结果,但最初,它是JDOM的一种智能分支。它合并了许多超出基本XML文档表示的功能,包括集成的XPath支持、XML Schema支持以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项,它通过DOM4J API和标准DOM接口具有并行访问功能。从2000下半年开始,它就一直处于开发之中。 

      为支持所有这些功能,DOM4J使用接口和抽象基本类方法。DOM4J大量使用了API中的Collections类,但是在许多情况下,它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是,虽然DOM4J付出了更复杂的API的代价,但是它提供了比JDOM大得多的灵活性。 

      在添加灵活性、XPath集成和对大文档处理的目标时,DOM4J的目标与JDOM是一样的:针对Java开发者的易用性和直观操作。它还致力于成为比JDOM更完整的解决方案,实现在本质上处理所有Java/XML问题的目标。在完成该目标时,它比JDOM更少强调防止不正确的应用程序行为。 

      DOM4J是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML,特别值得一提的是连Sun的JAXM也在用DOM4J.

  • 代码实现(根据参考官方文档Quick Start----由于dom4j为第三方开发工具,记得导入相关架包):

package com.itheima.util;

import java.io.FileOutputStream;

import org.dom4j.Document;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

public class Dom4jParserUtil {
	public static Document getDocument(String url) {
		SAXReader reader = null;
		Document document = null;
		try {
			reader = new SAXReader();
			document = reader.read(url);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return document;
	}

	public static void writeDocument2Xml(Document document, String url) {
		try {
			// Pretty print the document to System.out
			OutputFormat format = OutputFormat.createPrettyPrint();
			XMLWriter writer = new XMLWriter(new FileOutputStream(url), format);
			writer.write(document);
			writer.close();	
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

  • 结合XPathTutorial结合使用

package com.itheima.junit;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.junit.Test;
import com.itheima.util.Dom4jParserUtil;
public class Dom4jParserXPath {
	/*
	 * 1、得到某个具体的节点内容
	 * 2、遍历所有元素节点
	 * 3、修改某个元素节点的主体内容
	 * 4、向指定元素节点中增加子元素节点
	 * 5、向指定元素节点上增加同级元素节点(父结点.insertBefore(new,old))
	 * 6、删除指定元素节点
	 * 7、操作XML文件属性
	 */
	//1、得到某个具体的节点内容  获取第二个本的作者 
	private static String url = "src//books.xml";
	@Test
	public void test1(){
		Document document=Dom4jParserUtil.getDocument(url);
		//Element root = document.getRootElement();
		//Element secondBookEle = (Element) root.elements("书").get(1);
		//String text=secondBookEle.element("作者").getText();
		Element authorEle=(Element) document.selectSingleNode("/书架/书[2]/作者");
		System.out.println(authorEle.getText());
	}
	//2、遍历所有元素节点
	@Test
	public void test2(){
		Document document=Dom4jParserUtil.getDocument(url);
		Element root = document.getRootElement();
		walkTree(root);
	}
	private void walkTree(Element element){
		System.out.println(element.getName());
		for(int i=0;i<element.nodeCount();i++){
			Node node = element.node(i);
			if(node instanceof Element){
				walkTree((Element) node);
			}
		}
	}
	//3、修改某个元素节点的主体内容 将第二本书的售价改为500
	@Test
	public void test3(){
		Document document=Dom4jParserUtil.getDocument(url);
		//Element root = document.getRootElement();
		Element salePriceEle = (Element) document.selectSingleNode("/书架/书[2]/售价");
		salePriceEle.setText("500");
		Dom4jParserUtil.writeDocument2Xml(document, url);
	}
	//4、向指定元素节点中增加子元素节点  在第二本书中售价之后添加<批发价>600</批发价>
	@Test
	public void test4(){
		Document document=Dom4jParserUtil.getDocument(url);
//		Element root = document.getRootElement();
		Element secondBookEle = (Element) document.selectSingleNode("/书架/书[2]");
		Element priceEle = DocumentHelper.createElement("批发价");
		priceEle.setText("600");
		secondBookEle.add(priceEle);
		Dom4jParserUtil.writeDocument2Xml(document, url);
	}
	//5、向指定元素节点上增加同级元素节点 在第二本中售价之前添加<内部价>714</内部价>
	@SuppressWarnings("unchecked")
	@Test
	public void test5(){
		Document document=Dom4jParserUtil.getDocument(url);
//		Element root = document.getRootElement();
		Element secondBookEle = (Element) document.selectSingleNode("/书架/书[2]");
		Element innerpriceEle = DocumentHelper.createElement("内部价");
		innerpriceEle.setText("714");
		secondBookEle.elements().add(2, innerpriceEle);
		Dom4jParserUtil.writeDocument2Xml(document, url);
	}
	//6、删除指定元素节点   在第二本书中删除<批发价>标签 
	@Test
	public void test6(){
		Document document=Dom4jParserUtil.getDocument(url);
//		Element root = document.getRootElement();
		Element secondBookEle =  (Element) document.selectSingleNode("/书架/书[2]");
//		Element price = secondBookEle.element("批发价");
		Element price = (Element) document.selectSingleNode("/书架/书[2]/批发价");
		secondBookEle.remove(price);
		Dom4jParserUtil.writeDocument2Xml(document, url);
	}
	//7、操作XML文件属性  在 第一本书添加id属性,如<书 id="l7814">
	@Test
	public void test7(){
		Document document=Dom4jParserUtil.getDocument(url);
//		Element root = document.getRootElement();
		Element firstBookEle =  (Element) document.selectSingleNode("/书架/书[1]");
		firstBookEle.addAttribute("id","y11");
		Dom4jParserUtil.writeDocument2Xml(document, url);
	}
}

5.关于Sax和Dom解析XML的区别

  1.  为 XML 文档的已解析版本定义了一组接口。解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以使用 DOM 接口来操作这个树结构。优点:整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能;缺点:将整个文档调入内存(包括无用的节点),浪费时间和空间;使用场合:一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、CPU)。

  2.  为解决DOM的问题,出现了SAX。SAX ,事件驱动。当解析器发现元素开始、元素结束、文本、文档的开始或结束等时,发送事件,程序员编写响应这些事件的代码,保存数据。优点:不用事先调入整个文档,占用资源少;SAX解析器代码比DOM解析器代码小,适于Applet,下载。缺点:不是持久的;事件过后,若没保存数据,那么数据就丢了;无状态性;从事件中只能得到文本,但不知该文本属于哪个元素;使用场合:Applet;只需XML文档的少量内容,很少回头访问;机器内存少;

    相关参考链接:1.解析XML常用技术分析(各种方式优劣之处)

                      2.android解析XML文档的各种方式







你可能感兴趣的:(2014-06-30 Web中XML的学习(2)-----XML文档Java语言解析)