`
lifaming15
  • 浏览: 58693 次
  • 来自: ...
文章分类
社区版块
存档分类

Java与XML读写之SAX篇

阅读更多

我们还是沿用讲DOM的时候使用的那个文档例子,但首先,我们先看一个简单一些的应用,我们希望能够统计一下XML文件中各个标签出现的次数。这个例子很简单,但是足以阐述SAX编程的基本思路了。

一开始当然还是import语句了:

import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import java.util.*;
import java.io.*;

然后,我们创建一个继承于DefaultHandler的类,具体的程序逻辑在这儿可以暂且放在一边,要注意的是程序的结构:

public class SAXCounter extends DefaultHandler {
private Hashtable tags; //这个Hashtable用来记录tag出现的次数
// 处理文档前的工作
public void startDocument() throws SAXException {
tags = new Hashtable();//初始化Hashtable
}
//对每一个开始元属进行处理
public void startElement(String namespaceURI, String localName,
String rawName, Attributes atts)
throws SAXException
{
String key = localName;
Object value = tags.get(key);
if (value == null) {
// 如果是新碰到的标签,这在Hastable中添加一条记录
tags.put(key, new Integer(1));
} else {
// 如果以前碰到过,得到其计数值,并加1
int count = ((Integer)value).intValue();
count++;
tags.put(key, new Integer(count));
}
}
//解析完成后的统计工作
public void endDocument() throws SAXException {
Enumeration e = tags.keys();
while (e.hasMoreElements()) {
String tag = (String)e.nextElement();
int count = ((Integer)tags.get(tag)).intValue();
System.out.println("Tag <" + tag + "> occurs " + count
+ " times");
}
}
//程序入口,用来完成解析工作
static public void main(String[] args) {
String filename = null;
boolean validation = false;
filename="links.xml";
SAXParserFactory spf = SAXParserFactory.newInstance();
XMLReader xmlReader = null;
SAXParser saxParser=null;
try {
// 创建一个解析器SAXParser对象
saxParser = spf.newSAXParser();
// 得到SAXParser中封装的SAX XMLReader
xmlReader = saxParser.getXMLReader();
} catch (Exception ex) {
System.err.println(ex);
System.exit(1);
}
try {
//使用指定的ContentHandler,解析给XML文件,这儿要注意的是,为了
//程序的简单起见,这儿将主程序和ContentHandler放在了一起。实际上
//main方法中所作的所有事情,都与ContentHandler无关。
xmlReader.parse(new File(filename),new SAXCounter());
} catch (SAXException se) {
System.err.println(se.getMessage());
System.exit(1);
} catch (IOException ioe) {
System.err.println(ioe);
System.exit(1);
}
}
}

我们来看看这段程序作了些什么,在main()方法中,主要做的就是创建解析器,然后解析文档。实际上,在这儿创建SAXParser对象的时候,为了使程序代码于具体的解析器无关,使用了同DOM中一样的设计技巧:通过一个SAXParserFactory类来创建具体的SAXParser对象,这样,当需要使用不同的解析器的时候,要改变的,只是一个环境变量的值,而程序的代码可以保持不变。这就是FactoryMethod模式的思想。在这儿不再具体讲了,如果还有不明白的,可以参看上面DOM中的解释,原理是一样的。

不过在这儿还有一点点要注意的地方,就是SAXParser类和XMLReader类之间的关系。你可能有些迷糊了吧,实际上SAXParser是JAXP中对XMLReader的一个封装类,而XMLReader是定义在SAX2.0种的一个用来解析文档的接口。你可以同样的调用SAXParser或者XMLReader中的parser()方法来解析文档,效果是完全一样的。不过在SAXParser中的parser()方法接受更多的参数,可以对不同的XML文档数据源进行解析,因而使用起来要比XMLReader要方便一些。

这个例子仅仅涉及了SAX的一点皮毛,而下面的这个,可就要高级一些了。下面我们要实现的功能,在DOM的例子中已经有实现了,就是从XML文档中读出内容并格式化输出,虽然程序逻辑看起来还是很简单,但是SAX可不比DOM哦,看着吧。

前面说过,当遇到一个开始标签的时候,在startElement()方法中,我们并不能够得到这个标签在XML文档中所处的位置。这在处理XML文档的时候是个大麻烦,因为在XML中标签的语义,有一部分是由其所处的位置所决定的。而且在一些需要验证文档结构的程序中,这更是一个问题。当然,没有解决不了的问题了,我们可以使用一个栈来实现对文档结构的纪录。

栈的特点是先进先出,我们现在的想法是,在startElemnt()方法中用push将这个标签的名字添加到栈中,在endElement()方法中在把它pop出来。我们知道对一个结构良好的XML而言,其嵌套结构是完备的,每一个开始标签总会对应一个结束标签,而且不会出现标签嵌套之间的错位。因而,每一次startElement()方法的调用,必然会对应一个endElement()方法的调用,这样push和pop也是成对出现的,我们只需要分析栈的结构,就可以很容易的知道当前标签所处在文档结构中的位置了。

public class SAXReader extends DefaultHandler {
java.util.Stack tags=new java.util.Stack();
//--------------XML Content-------------
String text=null;
String url=null;
String author=null;
String description=null;
String day=null;
String year=null;
String month=null;
//----------------------------------------------
public void endDocument() throws SAXException {
System.out.println("------Parse End--------");
}
public void startDocument() throws SAXException {
System.out.println("------Parse Begin--------");
}
public void startElement(String p0, String p1, String p2, Attributes p3) throws SAXException {
tags.push(p1);
}
public void endElement(String p0, String p1, String p2) throws SAXException {
tags.pop();
//一个link节点的信息收集齐了,将其格式化输出
if (p1.equals("link")) printout();
}
public void characters(char[] p0, int p1, int p2) throws SAXException {
//从栈中得到当前节点的信息
String tag=(String) tags.peek();
if (tag.equals("text")) text=new String(p0,p1,p2);
else if (tag.equals("url")) url=new String(p0,p1,p2);
else if (tag.equals("author")) author=new String(p0,p1,p2);
else if (tag.equals("day")) day=new String(p0,p1,p2);
else if (tag.equals("month")) month=new String(p0,p1,p2);
else if (tag.equals("year")) year=new String(p0,p1,p2);
else if (tag.equals("description")) year=new String(p0,p1,p2);
}
private void printout(){
System.out.print("Content: ");
System.out.println(text);
System.out.print("URL: ");
System.out.println(url);
System.out.print("Author: ");
System.out.println(author);
System.out.print("Date: ");
System.out.println(day+"-"+month+"-"+year);
System.out.print("Description: ");
System.out.println(description);
System.out.println();
}
static public void main(String[] args) {
String filename = null;
boolean validation = false;
filename="links.xml";
SAXParserFactory spf = SAXParserFactory.newInstance();

这个例子仅仅涉及了SAX的一点皮毛,而下面的这个,可就要高级一些了。下面我们要实现的功能,在DOM的例子中已经有实现了,就是从XML文档中读出内容并格式化输出,虽然程序逻辑看起来还是很简单,但是SAX可不比DOM哦,看着吧。

前面说过,当遇到一个开始标签的时候,在startElement()方法中,我们并不能够得到这个标签在XML文档中所处的位置。这在处理XML文档的时候是个大麻烦,因为在XML中标签的语义,有一部分是由其所处的位置所决定的。而且在一些需要验证文档结构的程序中,这更是一个问题。当然,没有解决不了的问题了,我们可以使用一个栈来实现对文档结构的纪录。

栈的特点是先进先出,我们现在的想法是,在startElemnt()方法中用push将这个标签的名字添加到栈中,在endElement()方法中在把它pop出来。我们知道对一个结构良好的XML而言,其嵌套结构是完备的,每一个开始标签总会对应一个结束标签,而且不会出现标签嵌套之间的错位。因而,每一次startElement()方法的调用,必然会对应一个endElement()方法的调用,这样push和pop也是成对出现的,我们只需要分析栈的结构,就可以很容易的知道当前标签所处在文档结构中的位置了。

public class SAXReader extends DefaultHandler {
java.util.Stack tags=new java.util.Stack();
//--------------XML Content-------------
String text=null;
String url=null;
String author=null;
String description=null;
String day=null;
String year=null;
String month=null;
//----------------------------------------------
public void endDocument() throws SAXException {
System.out.println("------Parse End--------");
}
public void startDocument() throws SAXException {
System.out.println("------Parse Begin--------");
}
public void startElement(String p0, String p1, String p2, Attributes p3) throws SAXException {
tags.push(p1);
}
public void endElement(String p0, String p1, String p2) throws SAXException {
tags.pop();
//一个link节点的信息收集齐了,将其格式化输出
if (p1.equals("link")) printout();
}
public void characters(char[] p0, int p1, int p2) throws SAXException {
//从栈中得到当前节点的信息
String tag=(String) tags.peek();
if (tag.equals("text")) text=new String(p0,p1,p2);
else if (tag.equals("url")) url=new String(p0,p1,p2);
else if (tag.equals("author")) author=new String(p0,p1,p2);
else if (tag.equals("day")) day=new String(p0,p1,p2);
else if (tag.equals("month")) month=new String(p0,p1,p2);
else if (tag.equals("year")) year=new String(p0,p1,p2);
else if (tag.equals("description")) year=new String(p0,p1,p2);
}
private void printout(){
System.out.print("Content: ");
System.out.println(text);
System.out.print("URL: ");
System.out.println(url);
System.out.print("Author: ");
System.out.println(author);
System.out.print("Date: ");
System.out.println(day+"-"+month+"-"+year);
System.out.print("Description: ");
System.out.println(description);
System.out.println();
}
static public void main(String[] args) {
String filename = null;
boolean validation = false;
filename="links.xml";
SAXParserFactory spf = SAXParserFactory.newInstance();

SAXParser saxParser=null;
try {
saxParser = spf.newSAXParser();
} catch (Exception ex) {
System.err.println(ex);
System.exit(1);
}
try {
saxParser.parse(new File(filename),new SAXReader());
} catch (SAXException se) {
System.err.println(se.getMessage());
System.exit(1);
} catch (IOException ioe) {
System.err.println(ioe);
System.exit(1);
}
}
}

在这儿虽然没有使用到栈的分析,但实际上栈的分析是一件很容易的事情,应为java.util.Stack继承了java.util.Vector类,而且Stack中的元素是按栈的结构由底至上排列的,因个,我们可以使用Vector类的size()方法来得到Stack的元素个数,还可以使用Vector的get(int)方法来得到具体的每一个元属。实际上,如果把Stack的元素从底向上逐一排列出来,我们就得到了从XML根节点到当前节点的一条唯一的路径,有了这条路径的信息,文档的结构就在清楚不过了。

小节
好了,到这儿为止,我们已经掌握了对于XML编程的两大利器:DOM和SAX,也知道了该如何在一个Java程序中使用它们。DOM编程相对简单,但是速度比较慢,占用内存多,而SAX编程复杂一些,但是速度快,占用内存少。所以,我们应该根据不同的环境选择使用不同的方法。大部分的XML应用基本都可以用它们来解决。需要特别说明的是,DOM和SAX其实都是语言无关的,并非Java所独有,也就是说,只要有相应的语言实现,DOM和SAX可以应用在任何面向对象的语言中。

上面我们介绍了XML文档的读入,内容提取,以及文档添加和修改的一些方法。还有一类的问题就是XML文档的转换,虽然用DOM和SAX也可以解决,但是实现起来很复杂,而应用XSLT就会简单许多。这个问题,笔者将会在以后的文章中再和大家详细讨论。

分享到:
评论

相关推荐

    java读写xml文件的方法

    介绍了如何通过java来读写xml的方法,其中介绍了几种方法,如:DOM、SAX、JDOM、JAXB、dom4j.

    DOM、SAX、JDOM、DOM4J读写xml文档

    总结DOM、SAX、JDOM、DOM4J读写xml文档的多种方法。

    xmlbean轻轻松松读写XML的利器

     Java提供了SAX和DOM两种方式用于解析XML,但即便如此,要读写一个稍微复杂的XML,也不是一件容易的事.    二、XMLBean简介    Hibernate已经成为目前流行的面向Java环境的对象/关系数据库映射工具.    在...

    JavaXml读写操作四种方式汇总

    涵盖了DOM、SAX、JDOM和DOM4J四种方式,读写xml。都给出了具体例子,都是可执行的。

    Android读写XML.docx

    首先介绍下Android SDK与Java SDK在读写XML文件方面,数据包之间的关系。Android 平台最大的一个优势在于它利用了 Java 编程语言。Android SDK 并未向标准 Java Runtime Environment (JRE) 提供一切可用功能,但它...

    jsp操作xml源码,解析器为DOM和SAX

    利用JSP直接读写XML文件,分别用DOM解析器和SAX解析器加以实现,非常适合初学者入门,作为一个了解jsp与XML的台阶

    4种xml读写技术比较

    XML的四种解析器(dom,sax,jdom,dom4j)原理及性能比较

    JAVA_API1.6文档(中文)

    javax.xml.bind.annotation.adapters XmlAdapter 及其规范定义的子类允许任意 Java 类与 JAXB 一起使用。 javax.xml.bind.attachment 此包由基于 MIME 的包处理器实现,该处理器能够解释并创建基于 MIME 的包格式的...

    XML解析教程

    如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML,特别值得一提的是连Sun的JAXM(Java API for XML Messaging )也在用DOM4J。目前许多开源项目中大量采用DOM4J,例如大名鼎鼎的Hibernate也用DOM4J来读取XML...

    Java中读取XML 文件的知识点

    一、Dom4j下载及使用Dom4j读写XML简介: 要使用dom4j读写XML文档,需要先下载dom4j包,dom4j官方网站在 http://www.dom4j.org/ 解开后有两个包,仅操作XML文档的话把dom4j-1.6.1.jar加入工程就可以了,如果需要使用...

    JOX实现XML和JavaBean相互转化

    XML和JavaBean相互转化是一个非常有用的工作,用来读写xml的组件很多,比如dom4j, sax, JDom,Digester等,但是很多组件用起来很麻烦,今天给大家推荐一个超级简单的组件JOX, JOX是一套用户XML document和Java ...

    JavaAPI1.6中文chm文档 part1

    javax.xml.bind.annotation.adapters XmlAdapter 及其规范定义的子类允许任意 Java 类与 JAXB 一起使用。 javax.xml.bind.attachment 此包由基于 MIME 的包处理器实现,该处理器能够解释并创建基于 MIME 的包格式的...

    Java 1.6 API 中文 New

    javax.xml.bind.annotation.adapters XmlAdapter 及其规范定义的子类允许任意 Java 类与 JAXB 一起使用。 javax.xml.bind.attachment 此包由基于 MIME 的包处理器实现,该处理器能够解释并创建基于 MIME 的包格式的...

    java api最新7.0

    javax.xml.bind.annotation.adapters XmlAdapter 及其规范定义的子类允许任意 Java 类与 JAXB 一起使用。 javax.xml.bind.attachment 此包由基于 MIME 的包处理器实现,该处理器能够解释并创建基于 MIME 的包格式的...

    JavaAPI中文chm文档 part2

    javax.xml.bind.annotation.adapters XmlAdapter 及其规范定义的子类允许任意 Java 类与 JAXB 一起使用。 javax.xml.bind.attachment 此包由基于 MIME 的包处理器实现,该处理器能够解释并创建基于 MIME 的包格式的...

    使用dom4j操作xml

    Dom4j是一个开源的Java XML 解析处理工具,用来读写XML文件,它应用于Java平台,采用了Java集合框架并完全支持DOM, SAX和JAXP。具有性能优异、功能强大和极易使用的特点。可以作为解析XML文档析首先API。本文讲述了...

    [Java参考文档]

    javax.xml.bind.annotation.adapters XmlAdapter 及其规范定义的子类允许任意 Java 类与 JAXB 一起使用。 javax.xml.bind.attachment 此包由基于 MIME 的包处理器实现,该处理器能够解释并创建基于 MIME 的包格式的...

    读取XML的四种方法

    XML的解析方式分为四种:1、DOM解析;2、SAX解析;3、JDOM解析;4、DOM4J解析。此文当为完整的java文件,可以直接使用.

    java jdk实列宝典 光盘源代码

    17 java与xml 用dom处理xml文档; 用sax处理xml文档; 用xslt转换xml; 对象与xml的转换; 18 java mail 使用smtp协议发送简单邮件; 发送带附件的邮件; 给多人发送邮件; 使用pop3接收邮件; 19jsp与servlet 获取客户端...

Global site tag (gtag.js) - Google Analytics