StAX 概述

从一开始,Java API for XML Processing (JAXP) 就提供了两种方法来处理 XML:文档对象模型(DOM)方法是用标准的对象模型表示 XML 文档;Simple API for XML (SAX) 方法使用应用程序提供的事件处理程序来处理 XML。JSR-173 提出了一种面向流的新方法:Streaming API for XML (StAX)。其最终版本于 2004 年 3 月发布,并成为了 JAXP 1.4(将包含在即将发布的 Java 6 中)的一部分。

如其名称所暗示的那样,StAX 把重点放在流上。实际上,StAX 与其他方法的区别就在于应用程序能够把 XML 作为一个事件流来处理。将 XML 作为一组事件来处理的想法并不新颖(事实上 SAX 已经提出来了),但不同之处在于 StAX 允许应用程序代码把这些事件逐个拉出来,而不用提供在解析器方便时从解析器中接收事件的处理程序。

StAX 实际上包括两套处理 XML 的 API,分别提供了不同程度的抽象。基于指针的 API 允许应用程序把 XML 作为一个标记(或事件)流来处理;应用程序可以检查解析器的状态,获得解析的上一个标记的信息,然后再处理下一个标记,依此类推。这是一种低层 API,尽管效率高,但是没有提供底层 XML 结构的抽象。较为高级的基于迭代器的 API 允许应用程序把 XML 作为一系列事件对象来处理,每个对象和应用程序交换 XML 结构的一部分。应用程序只需要确定解析事件的类型,将其转换成对应的具体类型,然后利用其方法获得属于该事件的信息。

J2EE/XML开发者通常都是使用文档对象模型(DOM)API或简单的API for XML(SAX) API来分析XML文档。然而,这些API都有其缺点。其中,DOM API的缺点之一是消耗大量的内存,因为在该XML文档可以被导航之前,必须创建一个完整的XML文档的内存结构。而SAX API的缺点在于,它实例了一种推分析模型API,其中分析事件是由分析器生成的。比较之下,StAX则是基于一种拉分析模型。在本文中,你将首先创建你自己的XML文档,然后学习使用各种不同方法来对之进行分析;最后,我们使用事件生成的StAX拉方法。
  一、 推分析之于拉分析
  比较于推分析,拉分析具有如下一些优点:
  1. 在拉分析中,事件是由分析应用程序生成的,因此把分析规则提供到客户端而不是分析器。
  2. 拉分析的代码更简单并且它比推分析有更少的库。
  3. 拉分析客户端能同时读多个XML文档。
  4. 拉分析允许你过滤XML文档并且跳过分析事件。
  二、 了解StAX
  针对于XML的流式API(StAX),是在2004年3月的JSR 173规范中引入,这是一种针对XML的流式拉分析API。StAX是JDK 6.0提供的一种新特征,你可以从此处下载它的测试版本试用。
  一个推模型分析器不断地生成事件,直到XML文档被完全分析结束。但是,拉分析由应用程序进行调整;因此,分析事件是由应用程序生成的。这意味着,使用StaX,你可以推迟分析-在分析时跳过元素并且分析多个文档。在使用DOM API的时候,你必须把整个的XML文档分析成一棵DOM结构,这样也就降低了分析效率。而借助于StAX,在分析XML文档时生成分析事件。有关于StAX分析器与其它分析器的比较在此不多介绍。
  StAX API的实现是使用了Java Web服务开发(JWSDP)1.6,并结合了Sun Java流式XML分析器(SJSXP)-它位于javax.xml.stream包中。XMLStreamReader接口用于分析一个XML文档,而XMLStreamWriter接口用于生成一个XML文档。XMLEventReader负责使用一个对象事件迭代子分析XML事件-这与XMLStreamReader所使用的光标机制形成对照。本教程将基于JDK 6.0中的StAX实现来完成对一个XML文档的分析。
  其实,StaX仅仅是JDK 6.0所提供的XML新特征之一。新的JDK 6.0还提供了对针对于XML-Web服务的Java架构(JAX-WS)2.0,针对于XML绑定的Java API(JAXB) 2.0,XML数字签名API的支持,甚至还支持SQL:2003 'XML'数据类型。
  三、 初步安装
  如果你正在使用JDK 6.0,那么默认情况下,StAX API位于Classpath中。如果你在使用JWSDP 1.6,请把JWSDP 1.6 StAX API添加到classpath中。这需要把<jwsdp-1.6>\sjsxp\lib\ jsr173_api.jar和<jwsdp-1.6>\sjsxp\lib\sjsxp.jar添加到CLASSPATH变量中。在<jwsdp-1.6>目录下安装JWSDP 1.6。Jsr173_api.jar相应于JSR-173 API JAR,Sjsxp.jar相应于SJXSP实现JAR。 四、 使用XMLStreamWriter进行写操作
  首先,你要创建将待分析的XML文档。由StAX的XMLStreamWriter生成XML。然而,XMLStreamWriter的一个限制是,它不一定会生成良构的文档-而且生成的文档也不一定是有效的。你需要确保生成的XML文档是良构的。列表1是一个由XMLStreamWriter生成的原始XML文档的示例。
  在此,你试图使用XMLStreamWriter API生成列表1中的catalog.xml。在本节中的代码片断节选自XMLWriter.java应用程序,显示于列表2中。首先,你将导入StAX包类,请参考下列编码:

import javax.xml.stream.*; import javax.xml.stream.events.*; import javax.xml.stream.XMLOutputFactory;

  你要从一个XMLOutputFactory中得到你的XMLStreamWriter。因此,首先你必须创建一个新的XMLOutputFactory:

XMLOutputFactory outputFactory=XMLOutputFactory.newInstance();

  接下来,创建一个FileWriter以输出XML文档-它将被生成到一个XML文件中:

FileWriter output=new FileWriter(new File("C:/STAX/catalog.xml"));

  接下来,创建一个XMLStreamWriter:

XMLStreamWriter XMLStreamWriterr=outputFactory.createXMLStreamWriter(output);

  现在,使用writeStartDocument()方法创建一个文档开头。添加要在XML声明中指定的编码和版本(记住,指定的编码并不是生成的XML文档的编码)。如果你需要指定XML文档的编码,该怎么办呢?当从一个XMLOutputFactory对象创建一个XMLStreamWriter对象时,你会这样做:

XMLStreamWriter.writeStartDocument("UTF-8","1.0");

  使用writeComment()方法以输出一个注释:

XMLStreamWriter.writeComment("A OReilly Journal Catalog");

  使用writeProcessingInstruction()方法以输出一条处理指令:

XMLStreamWriter.writeProcessingInstruction("catalog","journal='OReilly'");

  使用writeStartElement()方法以输出'catalog'元素的开始(元素前缀和命名空间URI也可以在这个方法中指定的):

XMLStreamWriter.writeStartElement("journal","catalog","http://OnJava.com/Journal");

  使用writeNamespace()方法以添加'journal'命名空间声明(命名空间前缀和命名空间URI也是在这个方法中指定的):

XMLStreamWriter.writeNamespace("journal","http://OnJava.com/Journal");

  再次使用writeNamespace()方法添加xsi命名空间:

XMLStreamWriter.writeNamespace("xsi","http://www.w3.org/2001/XMLSchema-instance");

  使用writeAttribute()方法添加xsi:namespaceSchemaLocation属性:

XMLStreamWriter.writeAttribute("xsi:noNamespaceSchemaLocation","file://c:/Schemas/catalog.xsd");

  使用writeAttribute()方法添加'publisher'属性:

XMLStreamWriter.writeAttribute("publisher","OReilly");

  输出'journal'元素的开始。当增加一个新元素时,前一个元素的'>'括号也被添加上:

XMLStreamWriter.writeStartElement("journal","journal","http: //OnJava.com/Journal");

  使用writeAttribute()方法以添加'date'和'title'属性。然后,使用writeElement()方法以添加'article'和'title'元素。然后,使用writeCharacters()方法输出'title'元素的文本:

XMLStreamWriter.writeCharacters("Data Binding with XMLBeans");

  任何包含文本或子元素的元素都要有一个结束标签。使用writeEndElement()元素来添加'title'元素的结束标签:

XMLStreamWriter.writeEndElement();

  添加'author'元素和'journal'元素的结束标签。在writeEndElement()方法中,不必要指定元素前缀和命名空间URI。以类似方式添加另一个'journal'元素。然后,添加'catalog'元素的结束标签。最后,输出缓冲的数据:

XMLStreamWriter.flush();

  最后一步,关闭XMLStreamWriter。

XMLStreamWriter.close();

  这就是生成catalog.xml的过程。

  源码中的列表2展示了完整的Java应用程序-XMLWriter.java。这个应用程序可以作为一个命令行应用程序运行或在一种例如Eclipse这样的IDE中运行。

五、 使用XMLStreamReader进行分析
  通过使用XMLStreamReader API分析列表1中的文档,我们来详细分析一下其工作原理。XMLStreamReader使用一种光标分析XML文档。它的接口包含一个next()方法-由它分析下一个分析事件。getEventType()方法返回事件类型。后面的代码片断来自于XMLParser.java应用程序,详见列表3。
  在这个XMLParser.java应用程序中,首先,你要导入StAX类:

import javax.xml.stream.*; import javax.xml.stream.events.*; import javax.xml.stream.XMLInputFactory;

  然后,创建一个XMLInputFactory,由此你会得到一个XMLStreamReader:

XMLInputFactory inputFactory=XMLInputFactory.newInstance();

  现在,你需要创建一个InputStream,作为一个输入流,它描述了将被分析的文件。另外,还要从前面创建的XMLInputFactory对象中创建一个XMLStreamReader。

InputStream input=new FileInputStream(new File("C:/STAX/catalog.xml")); XMLStreamReader xmlStreamReader =inputFactory.createXMLStreamReader(input);

  如果更多分析事件可用,hasNext()方法返回true。然后,使用next()方法获得下一个分析事件:

int event=xmlStreamReader.next();

  比较于SAX分析,StAX分析的优点是,一个分析事件可以被跳过-通过调用next()方法,详见下面的代码。例如,如果分析事件类型为ENTITY_DECLARATION,那么开发者可以决定是要从当前事件中获得事件信息,还是检索下一个事件:

If(event.getEventType()==XMLStreamConstants.ENTITY_DECLARATION){ int event=xmlStreamReader.next(); }

  通过不调用next()方法,分析也可以被推迟。next()方法返回int,它代表了一个分析事件-通过使用一个XMLStreamConstants常量指定。

  XMLStreamReader所返回的不同的事件类型列举于表格1中。

事件类型 描述
START_DOCUMENT 一个文档的开始
START_ELEMENT 一个元素的开始
ATTRIBUTE 一个元素属性
NAMESPACE 一个命名空间声明
CHARACTERS 字符可以是文本,或是一个空格
COMMENT 一个注释
SPACE 可忽略的空格
PROCESSING_INSTRUCTION 处理指令
DTD 一个DTD
ENTITY_REFERENCE 一个实体参考
CDATA Cdata节
END_ELEMENT 结束元素
END_DOCUMENT 结束文档
ENTITY_DECLARATION 一个实体声明
NOTATION_DECLARATION 一个标志声明

        表格1.XMLStreamReader事件

  这些不同的分析事件能够使你获得XML文档中的数据和元数据。如果分析事件类型是START_DOCUMENT,那么你将使用getEncoding()方法获得XML文档中的指定编码,而你将使用getVersion()方法返回XML文档的XML版本。

  同样,如果你在使用一个START_ELEMENT事件类型工作,那么你将使用getPrefix()方法来返回元素前缀并且使用getNamespaceURI来返回元素前缀命名空间或默认命名空间。为了获得元素的本地命名,你将使用getLocalName()方法并且使用getAttributesCount()方法获得属性数目。你将使用getAttributePrefix(i)方法得到一个指定的属性索引i的属性前缀,而使用getAttributeNamespace(i)方法取得属性命名空间。使用getAttributeLocalName(i)方法获得属性本地命名,使用getAttributeValue(i)方法获得属性值。如果事件类型是CHARACTERS或COMMENT,则使用getText()方法获得相应的文本。

  列表4显示了示例XML文档,catalog.xml,的分析输出结果。

  列表3显示了用于分析XML文档的Java应用程序。你可以从命令行上或在一种例如Eclipse这样的IDE中来运行该应用程序。记住:如果你没有首先运行XMLWriter.java应用程序而运行XMLParser.java(见源码中的列表2),那么你需要把catalog.xml(见源码中的列表1)复制到C:/StAX目录下。

六、 使用XMLEventReader进行分析
  本节将向你展示如何使用XMLEventReader来分析catalog.xml。XMLEventReader接口使用一个事件对象迭代算子分析一个XML文档;通过这种方式,一个XML事件生成一个XMLEvent对象。XMLEventReader类似于XMLStreamReader-分析事件是由StAX分析器生成的。然而,XMLEventReader比XMLStreamReader有一个优点:通过使用XMLEventReader,一个应用程序可以使用peek()方法来"偷看"下一个事件,而不必从流中读取事件。这样,一个应用程序客户端可以决定是否有必要分析下一个事件。本节中的代码片断节选自XMLEventParser.java应用程序,请参见列表5。
  首先,导入StAX类:

import javax.xml.stream.*; import javax.xml.stream.events.*; import javax.xml.stream.XMLInputFactory;

  接下来,创建一个XMLInputFactory,由它获得一个XMLEventReader对象:

XMLInputFactory inputFactory=XMLInputFactory.newInstance(); InputStream input=new FileInputStream(new File("C:/STAX/catalog.xml")); XMLEventReader xmlEventReader =inputFactory.createXMLEventReader(input);

  在StAX中,XML文档事件是通过XMLEvent对象描述的。使用nextEvent()方法来遍历XMLEventReader对象以获得下一个事件:

XMLEvent event=xmlEventReader.nextEvent();

  使用getEventType()方法来获得事件类型(请参考表格1)。XMLEvent接口还提供布尔方法来获得事件类型。例如,isStartDocument()返回true,如果事件是开始文档类型。在下列代码中,事件是开始元素类型,因此一个StartElement对象可以从这个XMLEvent接口获得:

if(event.isStartElement()){  StartElement startElement=event.asStartElement(); }

  使用getAttributes()方法获得元素属性:

Iterator attributes=startElement.getAttributes();

  这个Iterator描述了一个javax.xml.stream.events.Attribute对象。使用next()方法遍历该Iterator。

Attribute attribute=(javax.xml.stream.events.Attribute)(attributes.next());

  最后,使用getName()方法获得属性命名,使用getValue()方法获得属性值。

  列表5显示出分析该XML文档的Java应用程序。应用程序XMLEventReader可以作为一个命令行应用程序运行,或在一种例如Eclipse这样的IDE中运行。记住:如果你运行XMLWriter.java或XMLParser.java应用程序而不首先运行XMLEventParser.java应用程序,那么你将需要把catalog.xml复制到C:/StAX目录下。

  最终,基于拉的事件生成把事件规则提供到分析器应用程序而不是提供到分析器。

[转载] 使用StAX解析xml的更多相关文章

  1. [置顶] stax解析xml文档的6种方式

    原文链接:http://blog.csdn.net/u011593278/article/details/9745271 stax解析xml文档的方式: 基于光标的查询: 基于迭代模型的查找: 基于过 ...

  2. webservice04#对象与xml转换-jaxb#Stax解析xml#新建修改xml

    1,Student类 package com.yangw.xml; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement / ...

  3. 转载 VC轻松解析XML文件 - CMarkup类的使用方法

    VC轻松解析XML文件 - CMarkup类的使用方法http://www.cctry.com/thread-3866-1-1.html VC解析XML文件的工具有很多,CMarkup, tinyXM ...

  4. Stax解析XML示例代码

    package org.itat.stax; import java.io.IOException; import java.io.InputStream; import javax.xml.pars ...

  5. 基于Woodstox的StAX 2 (Streaming API for XML)解析XML

    StAX (Streaming API for XML)面向流的拉式解析XML,速度快.占用资源少,非常合适处理大数据量的xml文件. 详细教程和说明可以参见以下几篇文章: 使用 StAX 解析 XM ...

  6. JAVA解析xml的四种方式比较

    1)DOM解析 DOM是html和xml的应用程序接口(API),以层次结构(类似于树型)来组织节点和信息片段,映射XML文档的结构,允许获取 和操作文档的任意部分,是W3C的官方标准 [优点] ①允 ...

  7. JavaEE实战——XML文档DOM、SAX、STAX解析方式详解

    原 JavaEE实战--XML文档DOM.SAX.STAX解析方式详解 2016年06月22日 23:10:35 李春春_ 阅读数:3445 标签: DOMSAXSTAXJAXPXML Pull 更多 ...

  8. java解析XML(转载)

    使用Dom4j解析XML dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的.dom4j是一个非常非常优秀的Java XML API,具有性能优异.功能强大和极端易用使用的 ...

  9. 【收藏用】--切勿转载JAVA 使用Dom4j 解析XML

    原帖地址 : http://blog.csdn.NET/yyywyr/article/details/38359049 解析XML的方式有很多,本文介绍使用dom4j解析xml. 1.环境准备 (1) ...

随机推荐

  1. ELK学习目录

    DAY1.elasticsearch和kibana环境搭建以及简单介绍 A:环境搭建配置 (1)java虚拟机安装:https://www.cnblogs.com/studybrother/p/108 ...

  2. Django创建对象的create和save方法

    Django的模型(Model)的本质是类,并不是一个具体的对象(Object).当你设计好模型后,你就可以对Model进行实例化从而创建一个一个具体的对象.Django对于创建对象提供了2种不同的s ...

  3. [Vue CLI 3] 配置解析之 indexPath

    在 vue.config.js 配置中有一个 indexPath 的配置,我们先看看它有什么用? 用来指定 index.html 最终生成的路径(相对于 outputDir) 先看看它的默认值:在文件 ...

  4. 外贸电子商务网站之Prestashop修改顶部导航

    如修改以上所示顶部导航. 如何在prestashop顶部导航栏添加链接,Module>Top horizontal menu点击进入Configure页面 1,在Settings 中看到 链接 ...

  5. Directx11教程(66) D3D11屏幕文本输出(1)

    原文:Directx11教程(66) D3D11屏幕文本输出(1)      在D3D10中,通过ID3DX10Font接口对象,我们可以方便的在屏幕上输出文字信息,一个DrawText函数就能解决所 ...

  6. 笔记:OSAL st 宏学习 do { x } while (__LINE__ == -1)

    笔记:OSAL st 宏学习 do { x } while (LINE == -1) #define st(x) do { x } while (__LINE__ == -1) 这段的意思是让代码可以 ...

  7. phonegap支付宝2.0移动快捷支付插件IOS版

    坑爹的支付宝,一两年都没有更新sdk了,这两天突然更新sdk,而且更新的变化特别大,所以只能对之前的支付宝快捷支付插件重新写了一遍. 这样既顺应了支付宝的更新,同时也支持了ios8. 废话少说,集成过 ...

  8. 获取表单所有字段 Post

    var params = $(".layui-form").serializeArray(); var values = {}; for (x in params) { value ...

  9. hdu 3466 01背包变形【背包dp】

    http://acm.hdu.edu.cn/showproblem.php?pid=3466 有两个物品P,Q,V分别为 3 5 6, 5 10 5,如果先dp第一个再dp第二个,背包容量至少要为3+ ...

  10. C++模板相关知识点总结

    1:在 C++ 中,模板是泛型编程的基础.模板是创建类或函数的蓝图或公式. 2:模板定义以关键字 template 开始,后接模板形参表,模板形参表是用尖括号括住的一个或多个模板形参的列表,形参之间以 ...