解析xml文档总结一

开发javaWEB项目,经常都要遇到xml文件,我们只要在xml配置项目的一些属性,那么项目就可以按我们所想的运作了。那么xml文件的数据是如何转化为系统可以识别的信息呢?这就需要解析xml文件了。

要解析xml文件就要有xml解析器,比较著名的有Apache的Xerces,微软的MSXML,Oracle的XMLParser等。如果系统要更换解析器就要修改源代码,那也太不人道了。幸运的事,这些解析器大都支持两套API:DOM和SAX,因此,我们针对DOM接口或SAX接口编程可以极大简化更改解析器时代码的修改。

另外,Oracle制定的JAXP规范在解析器之上提供了一层抽象,使我们可以独立于厂商API进行编程。在JavaSE中,JAXP的开发包由javax.xml,org.w3c.dom和org.xml.sax三个包组成。其中javax.xml.parsers包中定义了几个工厂方法用于加载DOM或SAX的实现类。其实现类可以很方便地更换,只要修改制定文件的一些配置即可。这个后面细讲。

因此针对JAXP编程可以随意更换解析器而不用修改任何的源代码。

以下具体说说DOM和SAX。

先说DOM吧。DOM把xml文档处理成一棵节点树,xml的元素,属性,文本,注释,数据段等在DOM中都有对应的类。且看类图:


有了这张图,再看后面的代码应该能容易一些。给出一个例子吧:

books.xml内容如下:

<?xml version="1.0" encoding="utf-8"?>
<books>
	<book name="java">
		<author>Bruce</author>
		<price>100</price>
	</book>
	<book name="c++">
		<author>Dinail</author>
		<price>80</price>
	</book>
</books>

代码如下:
import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class SimpleTest {
	
	public void test(){
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();//获得解析器实现类,获取方法后面讲
		try {
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document d = db.parse(new File("books.xml"));
			NodeList nl = d.getElementsByTagName("book");//获得所有的book节点		
			for(int i = 0;i < nl.getLength();i++){
				Element e = (Element)nl.item(i);//将book节点转换成元素
				String bookname = nl.item(i).getAttributes().item(0).getNodeValue();//获得book节点的属性列表,然后是第一个属性并得到其值
				Node n1 = e.getElementsByTagName("author").item(0);
				Node n2 = e.getElementsByTagName("price").item(0);
				String author = n1.getFirstChild().getNodeValue();
				String price = n2.getLastChild().getNodeValue();
				System.out.println("bookname:"+bookname+"\n\tauthor:"+author+"\n\tprice:"+price);
			}
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		new SimpleTest().test();
	}

}

应该注意的是,<book>与<author>之间有一个text节点,类似的,还有其他一些空白节点。其他的注释已经讲的清楚了,以下是输出:
bookname:java
	author:Bruce
	price:100
bookname:c++
	author:Dinail
	price:80

ok,回到上面的一个问题,如果要换解析器怎么办呢?或者说DocumentBuilderFactory.newInstance()是怎么找到实现类的呢?且听我细细道来。

关键之处在于javax.xml.parsers.DocumentBuilderFactory这个系统属性的设置。

可以通过System.setProperty("javax.xml.parsers.DocumentBuilderFactory","org.apache.parsers.jaxp.DocumentBuilderFactoryImp")

可以在执行时指定:java -Djavax.xml.parsers.DocumentBuilderFactory=org.apache.parsers.jaxp.DocumentBuilderFactoryImp

可以在jre/lib下添加jaxp.properties文件并添加一条记录:javax.xml.parsers.DocumentBuilderFactory=org.apache.parsers.jaxp.DocumentBuilderFactoryImp

如果都没找到,那就使用JDK自带的解析器了,在com\sun\org\apache\xerces\internal下


以下是SAX解析xml的一个例子,xml文件用上面那个:

import java.io.File;
import java.io.IOException;

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

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class SimpleTest {
	
	public void test(){
		SAXParserFactory spf = SAXParserFactory.newInstance();
		try {
			SAXParser sp = spf.newSAXParser();
			sp.parse(new File("books.xml"),new SAXHandler());
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new SimpleTest().test();
	}

}
class SAXHandler extends DefaultHandler{
	@Override
	public void startDocument() throws SAXException{
		System.out.println("start parsing");
	}
	
	@Override
	public void startElement(String uri,String localName,String qName,Attributes attr) throws SAXException{
		System.out.print("<"+qName);
		int length = attr.getLength();
		for(int i = 0;i < length;i++){
			System.out.print(" "+attr.getQName(i)+"="+attr.getValue(i));
		}
		System.out.print(">");
	}
	
	@Override
	public void characters(char[] buf,int start,int length) throws SAXException{
		System.out.print(new String(buf,start,length));
	}
	
	@Override
	public void endElement(String uri,String qName) throws SAXException{
		System.out.print("</"+qName+">");
	}
}
ok,可以看出,SAX使用基于事件的机制,解析xml文档时要指定处理类,处理类指定遇到开始元素怎么办,遇到文本怎么办,遇到结束怎么办等等,详细资料可以查阅相关文档。

相关文章

php输出xml格式字符串
J2ME Mobile 3D入门教程系列文章之一
XML轻松学习手册
XML入门的常见问题(一)
XML入门的常见问题(三)
XML轻松学习手册(2)XML概念