J2EE/XML
开发者通常都是使用文档对象模型
(DOM)API
或简单的
API for XML(SAX) API
来分析
XML
文档。然而,这些
API
都有其缺点。其中,
DOM API
的缺点之一是消耗大量的内存,因为在该
XML
文档可以被导航之前,必须创建一个完整的
XML
文档的内存结构。而
SAX API
的缺点在于,它实例了一种推分析模型
API
,其中分析事件是由分析器生成的。比较之下,
StAX
则是基于一种拉分析模型。在本文中,你将首先创建你自己的
XML
文档,然后学习使用各种不同方法来对之进行分析;最后,我们使用事件生成的
StAX
拉方法。
一、
Push
推分析之于拉分析
Pull
比较于推分析,拉分析具有如下一些优点:
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
中。
jsr173_api.jar
和
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
XMLOutputFactory outputFactory=XMLOutputFactory.newInstance();
//
接下来,创建一个
FileWriter
以输出
XML
文档
-
它将被生成到一个
XML
文件中:
FileWriter output=new FileWriter(new File("C:/STAX/catalog.xml"));
//
接下来,创建一个
XMLStreamWriter
:
XMLStreamWriter XMLStreamWriterr=outputFactory.createXMLStreamWriter(output);
//
添加要在
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
接口还提供布尔方法来获得事件类型。例如,
isStartDocum ent()
返回
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
目录下。
最终,基于拉的事件生成把事件规则提供到分析器应用程序而不是提供到分析器。
posted on 2006-09-17 22:24
Lizzie 阅读(427)
评论(1) 编辑 收藏 所属分类:
专业积木