Java中使用jaxp进行sax解析_动力节点Java学院整理

SAX解析XML文件采用事件驱动的方式进行,也就是说,SAX是逐行扫描文件,遇到符合条件的设定条件后就会触发特定的事件,回调你写好的事件处理程序。使用SAX的优势在于其解析速度较快,相对于DOM而言占用内存较少。而且SAX在解析文件的过程中得到自己需要的信息后可以随时终止解析,并不一定要等文件全部解析完毕。凡事有利必有弊,其劣势在于SAX采用的是流式处理方式,当遇到某个标签的时候,它并不会记录下以前所遇到的标签,也就是说,在处理某个标签的时候,比如在startElement方法中,所能够得到的信息就是标签的名字和属性,至于标签内部的嵌套结构,上层标签、下层标签以及其兄弟节点的名称等等与其结构相关的信息都是不得而知的。实际上就是把XML文件的结构信息丢掉了,如果需要得到这些信息的话,只能你自己在程序里进行处理了。所以相对DOM而言,SAX处理XML文档没有DOM方便,SAX处理的过程相对DOM而言也比较复杂。

SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器:

解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。

解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。

事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。

备注说明:SAX API中主要有四种处理事件的接口,它们分别是ContentHandler,DTDHandler, EntityResolver 和 ErrorHandler

这里使用最多的就是ContentHandler,仔细阅读 API文档,了解常用方法:startElement、endElement、characters等

 1.startElement方法说明

void startElement(String uri,
     String localName,
     String qName,
     Attributes atts)
     throws SAXException 

方法说明:

解析器在 XML 文档中的每个元素的开始调用此方法;对于每个 startElement 事件都将有相应的 endElement 事件(即使该元素为空时)。所有元素的内容都将在相应的 endElement 事件之前顺序地报告。

参数说明:

uri - 名称空间 URI,如果元素没有名称空间 URI,或者未执行名称空间处理,则为空字符串  
localName - 本地名称(不带前缀),如果未执行名称空间处理,则为空字符串  
qName - 限定名(带有前缀),如果限定名不可用,则为空字符串  
atts - 连接到元素上的属性。如果没有属性,则它将是空 Attributes 对象。在 startElement 返回后,此对象的值是未定义的

 2.endElement方法说明

void endElement(String uri, 

    String localName,
    String qName)
    throws SAXException接收元素结束的通知。 

SAX 解析器会在 XML 文档中每个元素的末尾调用此方法;对于每个 endElement 事件都将有相应的 startElement 事件(即使该元素为空时)。

参数:

uri - 名称空间 URI,如果元素没有名称空间 URI,或者未执行名称空间处理,则为空字符串  
localName - 本地名称(不带前缀),如果未执行名称空间处理,则为空字符串  
qName - 限定的 XML 名称(带前缀),如果限定名不可用,则为空字符串

3.characters方法

void characters(char[] ch,
    int start,
    int length)
    throws SAXException 

接收字符数据的通知,可以通过new String(ch,start,length)构造器,创建解析出来的字符串文本.

参数:

ch - 来自 XML 文档的字符  
start - 数组中的开始位置  
length - 从数组中读取的字符的个数

其它方法请参考api数据

下面我们就具体讲解sax解析的操作.

一.我们通过XMLReaderFactory、XMLReader完成,步骤如下

1.通过XMLReaderFactory创建XMLReader对象

XMLReader reader = XMLReaderFactory.createXMLReader();

2. 设置事件处理器对象

reader.setContentHandler(new MyDefaultHandler()); 

3.读取要解析的xml文件

FileReader fileReader =new FileReader(new File("src\\sax\\startelement\\web.xml")); 

4.指定解析的xml文件

reader.parse(new InputSource(fileReader)); 

案例:通过案例对uri、localName、qName和attribute参数有更加深入的了解

1.首先创建要解析的web.xml文件,内容如下

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
 xmlns:csdn="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 <csdn:display-name></csdn:display-name>
</web-app>
<!--
uri - 名称空间 URI,如果元素没有任何名称空间 URI,或者没有正在执行名称空间处理,则为空字符串。
xml namespace-xmlns
localName - 本地名称(不带前缀),如果没有正在执行名称空间处理,则为空字符串。
qName - 限定的名称(带有前缀),如果限定的名称不可用,则为空字符串。
attributes - 附加到元素的属性。如果没有属性,则它将是空的 Attributes 对象。
 --> 

2.创建解析测试类及事件处理的内部类代码如下

package sax.startelement;
import java.io.File;
import java.io.FileReader;
import org.junit.Test;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
public class Demo3 {
 @Test
 public void test() throws Exception {
  // 通过XMLReaderFactory创建XMLReader对象
  XMLReader reader = XMLReaderFactory.createXMLReader();
  // 设置事件处理器对象
  reader.setContentHandler(new MyDefaultHandler());
  // 读取要解析的xml文件
  FileReader fileReader = new FileReader(new File(
    "src\\sax\\startelement\\web.xml"));
  // 指定解析的xml文件
  reader.parse(new InputSource(fileReader));
 }
 // 自定义的解析类,通过此类中的startElement了解uri,localName,qName,Attributes的含义
 class MyDefaultHandler extends DefaultHandler {
  @Override
  public void startElement(String uri, String localName, String qName,
    Attributes attributes) throws SAXException {
   super.startElement(uri, localName, qName, attributes);
   System.out
     .println("--------------startElement开始执行--------------------------");
   System.out.println("uri:::" + uri);
   System.out.println("localName:::" + localName);
   System.out.println("qName:::" + qName);
   for (int i = 0; i < attributes.getLength(); i++) {
    String value = attributes.getValue(i);// 获取属性的value值
    System.out.println(attributes.getQName(i) + "-----" + value);
   }
   System.out
     .println("------------------startElement执行完毕---------------------------");
  }
 }
} 

3.程序运行的结果如下:

通过运行结果,希望你对uri,localName,qName有更加深入的了解.

二.我们通过SAXParserFactory、SAXParser、XMLReader完成,步骤如下

1.使用SAXParserFactory创建SAX解析工厂

SAXParserFactory spf = SAXParserFactory.newInstance();

2.通过SAX解析工厂得到解析器对象

SAXParser sp = spf.newSAXParser();

3.通过解析器对象得到一个XML的读取器

XMLReader xmlReader = sp.getXMLReader();

4.设置读取器的事件处理器

xmlReader.setContentHandler(new BookParserHandler());

5.解析xml文件

xmlReader.parse("book.xml");

说明:如果只是使用SAXParserFactory、SAXParser他们完成只需要如下3步骤

1.获取sax解析器的工厂对象

SAXParserFactory factory = SAXPar
serFactory.newInstance();

2.通过工厂对象 SAXParser创建解析器对象

SAXParser saxParser = factory.newSAXParser();

3.通过解析saxParser的parse()方法设定解析的文件和自己定义的事件处理器对象

saxParser.parse(new File("src//sax//sida.xml"), new MyDefaultHandler());

案例:解析出"作者"元素标签中的文本内容

1.需要解析的sida.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 四大名著[
<!ELEMENT 四大名著 (西游记,红楼梦)>
<!ATTLIST 西游记 id ID #IMPLIED>
]>
<四大名著>
 <西游记 id="x001">
  <作者>吴承恩</作者>
 </西游记>
 <红楼梦 id="x002">
  <作者>曹雪芹</作者>
 </红楼梦>
</四大名著> 

2.解析测试类和事件处理器类的实现代码

package sax;
import java.io.File;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.junit.Test;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SaxTest {
 @Test
 public void test() throws Exception {
  // 1.获取sax解析器的工厂对象
  SAXParserFactory factory = SAXParserFactory.newInstance();
  // 2.通过工厂对象 SAXParser创建解析器对象
  SAXParser saxParser = factory.newSAXParser();
  // 3.通过解析saxParser的parse()方法设定解析的文件和自己定义的事件处理器对象
  saxParser.parse(new File("src//sax//sida.xml"), new MyDefaultHandler());
 }
 // 自己定义的事件处理器
 class MyDefaultHandler extends DefaultHandler {
  // 解析标签开始及结束的的标识符
  boolean isOk = false;
  @Override
  public void startElement(String uri, String localName, String qName,
    Attributes attributes) throws SAXException {
   super.startElement(uri, localName, qName, attributes);
   // 当解析作者元素开始的时候,设置isOK为true
   if ("作者".equals(qName)) {
    isOk = true;
   }
  }
  @Override
  public void characters(char[] ch, int start, int length)
    throws SAXException {
   // TODO Auto-generated method stub
   super.characters(ch, start, length);
   // 当解析的标识符为true时,打印元素的内容
   if (isOk) {
    System.out.println(new String(ch, start, length));
   }
  }
  @Override
  public void endElement(String uri, String localName, String qName)
    throws SAXException {
   super.endElement(uri, localName, qName);
   // 当解析作者元素的结束的时候,设置isOK为false
   if ("作者".equals(qName)) {
    isOk = false;
   }
  }
 }
} 

3.程序运行结果如下:

(0)

相关推荐

  • Java下3中XML解析 DOM方式、SAX方式和StAX方式

    先简单说下前三种方式: DOM方式:个人理解类似.net的XmlDocument,解析的时候效率不高,占用内存,不适合大XML的解析:SAX方式:基于事件的解析,当解析到xml的某个部分的时候,会触发特定事件,可以在自定义的解析类中定义当事件触发时要做得事情:个人感觉一种很另类的方式,不知道.Net体系下是否有没有类似的方式?StAX方式:个人理解类似.net的XmlReader方式,效率高,占用内存少,适用大XML的解析:不过SAX方式之前也用过,本文主要介绍JAXB,这里只贴下主要代码: 复

  • java中使用sax解析xml的解决方法

    在java中,原生解析xml文档的方式有两种,分别是:Dom解析和Sax解析 Dom解析功能强大,可增删改查,操作时会将xml文档以文档对象的方式读取到内存中,因此适用于小文档 Sax解析是从头到尾逐行逐个元素读取内容,修改较为不便,但适用于只读的大文档 本文主要讲解Sax解析,其余放在后面 Sax采用事件驱动的方式解析文档.简单点说,如同在电影院看电影一样,从头到尾看一遍就完了,不能回退(Dom可来来回回读取) 在看电影的过程中,每遇到一个情节,一段泪水,一次擦肩,你都会调动大脑和神经去接收或

  • 使用jaxp进行dom解析_动力节点Java学院整理

    1.javax.xml.parsers 包中的DocumentBuilderFactory用于创建DOM模式的解析器对象 , DocumentBuilderFactory是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance方法 ,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回 2.调用 DocumentBuilderFactory.newInstance() 方法得到创建 DOM 解析器的工厂. 3.调用工厂对象的 newDocumentBuilder

  • java操作(DOM、SAX、JDOM、DOM4J)xml方式的四种比较与详解

    1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这个层次结构允许开发人员在树中寻找特定信息.分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作.由于它是基于信息层次的,因而DOM被认为是基于树或基于对象的.DOM以及广义的基于树的处理具有几个优点.首先,由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构作出更改.它还可以在任何时候在树中上下导航,而不是像SAX那

  • Java中使用DOM和SAX解析XML文件的方法示例

    dom4j介绍 dom4j的项目地址:http://sourceforge.net/projects/dom4j/?source=directory dom4j是一个简单的开源库,用于处理XML. XPath和XSLT,它基于Java平台,使用Java的集合框架,全面集成了DOM,SAX和JAXP. dom4j的使用 下载了dom4j项目之后,解压缩,将其jar包(我的当前版本叫做dom4j-1.6.1.jar)加入class path下面. (Properties->Java Build Pa

  • Java中使用jaxp进行sax解析_动力节点Java学院整理

    SAX解析XML文件采用事件驱动的方式进行,也就是说,SAX是逐行扫描文件,遇到符合条件的设定条件后就会触发特定的事件,回调你写好的事件处理程序.使用SAX的优势在于其解析速度较快,相对于DOM而言占用内存较少.而且SAX在解析文件的过程中得到自己需要的信息后可以随时终止解析,并不一定要等文件全部解析完毕.凡事有利必有弊,其劣势在于SAX采用的是流式处理方式,当遇到某个标签的时候,它并不会记录下以前所遇到的标签,也就是说,在处理某个标签的时候,比如在startElement方法中,所能够得到的信

  • Java中HashSet和HashMap的区别_动力节点Java学院整理

    什么是HashSet? HashSet实现了Set接口,它不允许集合中有重复的值,当我们提到HashSet时,第一件事情就是在将对象存储在HashSet之前,要先确保对象重写equals()和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有储存相等的对象.如果我们没有重写这两个方法,将会使用这个方法的默认实现.. public boolean add(Object o)方法用来在Set中添加元素,当元素值重复时则会立即返回false,如果成功添加的话会返回true. 什

  • Java中抽象类和接口的区别_动力节点Java学院整理

    接口 1 因为java不支持多重继承,所以有了接口,一个类只能继承一个父类,但可以实现多个接口,接口本身也可以继承多个接口. 2 接口里面的成员变量默认都是public static final类型的.必须被显示的初始化. 3 接口里面的方法默认都是public abstract类型的.隐式声明. 4 接口没有构造方法,不能被实例化. 5 接口不能实现另一个接口,但可以继承多个接口. 6 类如果实现了一个接口,那么必须实现接口里面的所有抽象方法,否则类要被定义为抽象类. 抽象类 1 如果将一个类

  • Java中HashTable和HashMap的区别_动力节点Java学院整理

    HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的区别.主要的区别有:线程安全性,同步(synchronization),以及速度. HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap allows one null key and any number of null values.,而Hashtable则不行).这就是说,HashMap中如果在表中没有发现搜索键,或者如

  • Java中线程的等待与唤醒_动力节点Java学院整理

    wait(), notify(), notifyAll()等方法介绍 在Object.java中,定义了wait(), notify()和notifyAll()等接口.wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁.而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程:notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程. Object类中关于等待/唤醒的API详细信息如下: notify()      

  • 探索Java中的equals()和hashCode()方法_动力节点Java学院整理

    equals()和hashCode()区别?  equals():反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值.  hashCode():计算出对象实例的哈希码,并返回哈希码,又称为散列函数.根类Object的hashCode()方法的计算依赖于对象实例的D(内存地址),故每个Object对象的hashCode都是唯一的:当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了. 之所以有hashCode方法,是因为在批量的对象比

  • 简述Java中进程与线程的关系_动力节点Java学院整理

    概述 进程与线程,本质意义上说, 是操作系统的调度单位,可以看成是一种操作系统 "资源" .Java 作为与平台无关的编程语言,必然会对底层(操作系统)提供的功能进行进一步的封装,以平台无关的编程接口供程序员使用,进程与线程作为操作系统核心概念的一部分无疑亦是如此.在 Java 语言中,对进程和线程的封装,分别提供了 Process 和 Thread 相关的一些类.本文首先简单的介绍如何使用这些类来创建进程和线程,然后着重介绍这些类是如何和操作系统本地进程线程相对应的,给出了 Java

  • Java中的clone方法详解_动力节点Java学院整理

    Java中对象的创建 clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象.所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象.那么在java语言中,有几种方式可以创建对象呢? 1 使用new操作符创建一个对象 2 使用clone方法复制一个对象 那么这两种方式有什么相同和不同呢? new操作符的本意是分配内存.程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间.分配完内存

  • Java中的FileInputStream 和 FileOutputStream 介绍_动力节点Java学院整理

    FileInputStream 和 FileOutputStream 介绍 FileInputStream 是文件输入流,它继承于InputStream. 通常,我们使用FileInputStream从某个文件中获得输入字节. FileOutputStream 是文件输出流,它继承于OutputStream. 通常,我们使用FileOutputStream 将数据写入 File 或 FileDescriptor 的输出流. FileInputStream 函数接口 FileInputStream

随机推荐