分享
 
 
 

JAXP: Coding for Parser & Transformer Independence

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

Author: Henry Chen 译者:李力

介绍

由于可扩展标记语言(XML)的易用性和轻携性,其近年来获得了极大的流行。它与Java结合起来,非常适用于可移植的数据和代码。每一个与XML文档打交道的Java程序员,无论是读数据,还是进行数据转换,都必须对Java API’s for XML Processing (JAXP)有一个很深的理解。编写XML解析器无关的代码有许多好处,JAXP API 是用于XML的,就像JDBC API是用于关系型数据库的。这篇介绍性的文章帮助开发者学习JAXP API,并让开发者对可插入层(pluggability layer)有一个很深的理解,这样,开发者就可以在他们的应用程序中自如的更换解析器。

JAXPack

SUN推出了一个用于XML的Java API 和架构,称其为Java XML Pack (JAXPack - http://java.sun.com/xml/javaxmlpack.html)。下载包中包括了现在行业中一些重要的标准。这篇文章中,我们将注意力放在JAXP(the API for XML Processing)上,Sybase的Easerver从版本3.6.1开始支持JAXP。

首先,我们看一下JAXP提供的解析能力,解析XML文档有两种最基本的方法, 基于事件的SAX和遍历树的DOM。开发者可以选择最适合他们需要的方法。让我们钻进去,深入的看一下这些API。

这篇文章中,我们用图1中的XML文档来阐述我们的例子。

SAX

Simple API for XML Parsing (SAX)是事件驱动的,它从头到尾遍历整个文档, 当它遇到一个语法结构时,它会通知运行它的程序,这些是通过事件处理接口ContentHandler, ErrorHandler, DTDHandler, 和 EntityResolver中的回调方法实现的。这些回调方法可以被开发者自定义实现来满足一些特殊的要求。图2描绘了SAX解析器解析文档是各种组件之间的关系。

我们将遍历图1中XML文档,并且给出SAX解析器一行一行的解析是调用回调方法的细节,在这个例子中,我们不包括对ignorableWhiteSpace方法调用。

现在你已经对SAX如何工作有一个总体的了解,接下来,让我们看一看用真真的Java代码实现的例子,我们实现的程序的完整代码可以在http://www.sybase.com/developer.上找到,出于这篇文章的目的,我将只用一些代码相关部分的片断。

public class SAXExample extends DefaultHandler {

SAXParserFactory factory = SAXParserFactory.newInstance();

SAXParser saxParser = factory.newSAXParser();

DefaultHandler handler = new SAXExample();

saxParser.parse( new File(argv[0]), handler)

注意我们继承了DefaultHandler Class, 这个类用一些空方法实现了ContentHandler, ErrorHandle, DTDHandler,和 EntityResolver接口,这样,程序员就可以只覆盖一些他们需要的方法。

在我们解析之前,我们首先需要通过调用newInstance方法,实例化一个SAXParserFactory,这个方法用某个特定的查找顺序来决定使用哪一个SAXParserFactory的实现,这就意味着,解析器更改时,代码无需重新编译。

一旦我们实例化了一个SAXParserFactory,我们可以设置三个选项,这些决定了随后如何产生SAXParser的对象。

SAXParserFactory 使namespace可用

SetValidating 打开验证

SetFeature 设定底层实现的特征

SAXParserFactory配置好后,我们调用newSAXParser方法来实例化一个JAXP SAXParser对象,这个对象包装了一个底层的SAX解析器,并且允许我们以厂商中立的方式与其交互,现在,我们就可以解析了。在这个例子中,我们用File对象作为输入,它还可以接受其他的输入源,如InputSource对象,InputStream 对象,或者Uniform Resource Identifier (URI)。

注意程序是如何使自己成为解析器的处理者(handler)的,这意味着解析器将调用SAXExampl中的回调方法的,当解析方法一行一行的解析XML文件时,我们的处理类中的回调事件就发生了。

DOM

Document Object Model (DOM)是将XML文档解析成树状对象的一套接口,每一个对象,或结点(node)都有一个用org.w3c.dom包中的接口表示的类型(type).如Element, Attribute,

Comment, 和Text。可以像操作其他任何树状数据结构一样来操作DOM树状对象,它允许随机访问XML文档中特定部分的数据,并且修改它,这些是SAX解析器做不到的。

这种方法的缺点是它非常占用内存和CPU资源,因为构建DOM树时需要将整个XML文档读入并保持在内存中。

让我们看一个例子:

public class DOMExample {

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

DocumentBuilder domParser = factory.newDocumentBuilder();

Document document = domParser.parse( new File(argv[0]) );

.

与SAX类似,我们首先用newInstance方法实例化一个DocumentBuilderFactory对象,同样类似SAXParserFactory,工厂可以配置用来处理namespace(命名空间)和validation(验证)。另外,还有一些其他可选的设置,但这已经超出了本文的范围。工厂对象准备好后,我们就可以创造一个DocumentBuilder对象,它可用来解析xml文件和创造Document对象,同样类似SAXParser的parse方法,Document对象可以接受InputSource对象,InputStream对象,或者URI。

Node thePhonebook = document.getDocumentElement();

NodeList personList = thePhonebook.getChildNodes();

Node currPerson = personList.item(0);

Node fullName = currPerson.getChildNodes().item(0);

Node firstName = fullName.getChildNodes().item(0);

Node lastName = fullName.getChildNodes().item(1);

Text firstNameText = (Text)firstName.getFirstChild();

Text lastNameText = (Text)lastName.getFirstChild();

Node phone = currPerson.getChildNodes().item(1);

Node workPhone = phone.getChildNodes().item(0);

Node homePhone = phone.getChildNodes().item(1);

Text workPhoneText = (Text)workPhone.getFirstChild();

Text homePhoneText = (Text)homePhone.getFirstChild();

一旦我们拥有了Document DOM对象,我们就可以像操作其他树一样操作它。getDocumentElement方法返回根元素,从根元素可以得到子节点的NodeList,并且可以处理它们。在DOM树结构的叶结点,我们可以找到Text对象,它继承了Node。调用getData方法可以返回字符串的值。如你所见,使用者在操作数据时必须对文档数据的结构有一个了解,而在SAX中,解析器仅仅对它遇到的数据反应。

但是,DOM最大的优点是它可以对数据结构进行修改,例如:

if (firstNameText.getData().equals("Richard") &&

lastNameText.getData().equals("Mullins")) {

homePhoneText.setNodeValue("(510)333-3333");

}

用setNodeValue方法可以改变DOM树中的数据,随后,我们将看XSLT如何将一个新树写入一个数据文件。

XSLT

XSL转换(XSLT)是将XML文档转换为其他XML文档或其他格式的文档(如HTML)的一组API, XML样式语言(XSL)在转换中作用巨大,用其定义的样式表包含了格式规则,指定了文档如何显示。

这里有一个例子,将DOM对象转换为XML文档:

//create a new DOMSource using the root node of an existing DOM tree

DOMSource source = new DOMSource(thePhonebook);

StreamResult result = new StreamResult(System.out);

TransformerFactory tFactory = TransformerFactory.newInstance();

Transformer transformer = tFactory.newTransformer();

transformer.transform(source, result);

我们首先用newInstance方法实例化一个TransformerFactory对象,它用特定的查找顺序来决定使用哪一个转换器实现。和SAX和DOM工厂一样,可以对TransformerFactory对象进行一些配置,来影响Transformer对象的创建。用newTransformer方法创建好Transformer对象后,就可以调用transform方法,它将一个Source对象(DOMSource,SAXSource, StreamSource)转换为Result对象(DOMResult, SAXResult, StreamResult)。

抽象层

前面已经提到过,用某种特定的查找顺序来决定使用哪个SAX, DOM 和XSLT的实现,下面的API定义了查找顺序:

.使用javax.xml.parsers.SAXParserFactory(或javax.xml.parsers.DocumentBuilderFactory)系统属性(system property)。

.使用JRE目录中“lib/jaxp.properties”属性文件定义的javax.xml.parsers.SAXParserFactory属性的值,这个值必须包括了实现类的全名。

.使用Service API,它可以在运行系统中使用的JAR文件中包括的META-INF/services/javax.xml.parsers.SAXParserFactory文件中查找类名。

.使用平台默认的SAXParserFactory实例。

使用DOM时,你只需将javax.xml.parsers.SAXParserFactory替换为javax.xml.parsers.DocumentBuilderFactory,类似,使用XSLT时,你用javax.xml.transform.TransformerFactory替换。

总结

如你所见,你写的代码只需与抽象层打交道。这保证了厂商的无关性,你可以快速和轻松的替换你的解析器的实现。解析XML文档时,Java开发者可以根据他们的需要设置两个选项。SAX是利用回调过程的事件驱动模型,而DOM是一种游历树的模型,它在操作数据前必须将XML文档解析成树,XSLT则可以将XML文档转换为另一种XML文档或者其他格式,如HTML。总之,JAXP非常的强大,灵活,它提供的简单可用的工具可以满足大多数Java开发者处理XML文档时的需要。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有