本文主要讲述两个xml的解析方式:DOM解析和SAX解析。
一、DOM解析步骤:
1.通过文档解析器的工厂对象DocumentBuilderFactory得到一个文档解析DocunmentBuilder对象builder
2.通过输入流对象is获取xml文件内容
3.通过解析器的parse方法解析输入流对象is,并转换成Document对象document
4.获取文档的根节点document.getDocumentElement();
5.判断是否有孩子节点
6.获取所有的子节点对象,并判断每个子节点对象的类型,以获取指定类型节点的数据
7.将获取节点中的值并赋给实体化对象
示例代码如下:
package www.youkuaiyun.com.activityg.xml;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import www.youkuaiyun.com.activityg.domain.City;
public class DOMXML {
public List<City> domXml() {
// 创建返回的集合对象
List<City> cities = new ArrayList<City>();
// 创建问文档解析器的工厂对象
DocumentBuilderFactory builderFactory = DocumentBuilderFactory
.newInstance();
try {
// 得到文档解析器对象
DocumentBuilder builder = builderFactory.newDocumentBuilder();
// 获取输入流对象
InputStream is = getClass().getClassLoader().getResourceAsStream(
"china.xml");
// 通过解析器的parse方法 解析is对象,转换成 Document对象
Document document = builder.parse(is);
// 返回的是文档的跟节点
Element rootElement = document.getDocumentElement();
// 判断是否有孩子节点
if (rootElement.hasChildNodes()) {
// 获取所有的子节点
NodeList nodeList = rootElement.getChildNodes();
// 遍历子节点
for (int i = 0; i < nodeList.getLength(); i++) {
// 获取子节点对象
Node node = nodeList.item(i);
// 元素节点的类型值:1 文本类型的类型节点值:3 属性节点的类型值:2
// 判断这个子节点是什么类型的子节点 文本节点 元素节点
if (node.getNodeType() == Element.ELEMENT_NODE) {
// 创建一个实体对象 保存元素节点值
City city = new City();
// 造型
Element element = (Element) node;
// 得到这个节点中的所有属性节点
NamedNodeMap map = element.getAttributes();
//-------------- 遍历属性节点开始-----------------------
for (int j = 0; j < map.getLength(); j++) {
// 获取具体的某个属性节点
Attr attr = (Attr) map.item(j);
// 具体判断
if ("cityname".equals(attr.getNodeName())) {
// 设置对象的属性值
city.setCityName(attr.getNodeValue());
} else if ("pyName".equals(attr.getNodeName())) {
city.setPyName(attr.getNodeValue());
} else if ("quName".equals(attr.getNodeName())) {
city.setQuName(attr.getNodeValue());
} else if ("state1".equals(attr.getNodeName())) {
city.setState1(attr.getNodeValue());
} else if ("state2".equals(attr.getNodeName())) {
city.setState2(attr.getNodeValue());
} else if ("stateDetailed".equals(attr
.getNodeName())) {
city.setStateDetailed(attr.getNodeValue());
} else if ("tem1".equals(attr.getNodeName())) {
city.setTem1(attr.getNodeValue());
} else if ("tem2".equals(attr.getNodeName())) {
city.setTem2(attr.getNodeValue());
} else if ("windState".equals(attr.getNodeName())) {
city.setWindState(attr.getNodeValue());
}
}
//-------------------遍历属性节点的结束-------------------------------
// 添加到集合中
cities.add(city);
}
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return cities;
}
}
DOM的优势主要表现在:易用性强,使用DOM时,将把所有的XML文档信息都存于内存中,并且遍历简单,支持XPath,增强了易用性。
DOM的缺点主要表现在:效率低,解析速度慢,内存占用量过高,对于大文件来说几乎不可能使用。另外效率低还表现在大量的消耗时间,因为使用DOM进行解析时,将为文档的每个element、attribute、processing-instrUCtion和comment都创建一个对象,这样在DOM机制中所运用的大量对象的创建和销毁无疑会影响其效率。
所以DOM解析适用于小型xml文档的解析。
二、SAX
SAX不像DOM那样建立一个完整的文档树,而是在读取文档时激活一系列事件,这些事件被推给事件处理器,然后由事件处理器提供对文档内容的访问。通过继承DefaultHandler,并重写其中的方法来实现对xml文档的解析。
SAX的优点在于内存消耗少,可以解析大文件。缺点在于Sax解析是按照xml文件的顺序一步一步的来解析,如果xml文档结构非常的复杂,则会给编程带来麻烦。
import java.io.InputStream;
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.helpers.DefaultHandler;
import com.xtlh.cn.entity.Book;
public class SaxParseService extends DefaultHandler{
private List<Book> books = null;
private Book book = null;
private String preTag = null;//作用是记录解析时的上一个节点名称
public List<Book> getBooks(InputStream xmlStream) throws Exception{
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
SaxParseService handler = new SaxParseService();
parser.parse(xmlStream, handler);
return handler.getBooks();
}
public List<Book> getBooks(){
return books;
}
@Override
public void startDocument() throws SAXException {
books = new ArrayList<Book>();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if("book".equals(qName)){
book = new Book();
book.setId(Integer.parseInt(attributes.getValue(0)));
}
preTag = qName;//将正在解析的节点名称赋给preTag
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("book".equals(qName)){
books.add(book);
book = null;
}
preTag = null;/**当解析结束时置为空。这里很重要,例如,当图中画3的位置结束后,会调用这个方法
,如果这里不把preTag置为null,根据startElement(....)方法,preTag的值还是book,当文档顺序读到图
中标记4的位置时,会执行characters(char[] ch, int start, int length)这个方法,而characters(....)方
法判断preTag!=null,会执行if判断的代码,这样就会把空值赋值给book,这不是我们想要的。*/
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if(preTag!=null){
String content = new String(ch,start,length);
if("name".equals(preTag)){
book.setName(content);
}else if("price".equals(preTag)){
book.setPrice(Float.parseFloat(content));
}
}
}
}
代码来自http://www.iteye.com/topic/763895三、DOM与SAX的区别
1.DOM把所有的XML文档信息都存于内存中
2.Sax无需一次把xml文件加载到内存中,采用的事件驱动的操作
3.应用场景不一样,dom适合复杂结构小型xml文档,sax适用于简单结构大型xml。
4.dom可以直接获取某个节点,Sax只能按步骤读取。