解析XML
DOM技术
DOM(Document Object Model,文档对象模型)早在XML之前已经存在,Microsoft Explorer中就嵌入了DOM模型。在应用程序中基于DOM的XML分析器将一个XML文档转换为一个对象模型的集合(通常称“DOM树”),来实现对XML文档数据的操作。通过DOM接口,应用程序可以在任何时候访问XML文档中的任何一部分数据,因此这种利用DOM接口的机制也被称为“随机访问机制”。
对于XML应用开发来说,DOM就是一个对象化的XML数据接口,即一个与语言和平台无关的标准接口规范。DOM接口提供了一种通过分层对象模型来访问XML文档信息的方式,这些分层对象模型依据XML的文档结构形成了一棵节点树。无论XML文档中所描述的是什么类型的信息,即便是制表数据、项目列表或一个文档,利用DOM所生成的模型都是节点树的形式。即DOM强制使用树模型来访问XML文档中的信息,由于XML本质上就是一种分层结构,所以这种描述方法是相当有效的。
DOM编程
DOM是与平台和语言无关的表示XML文档的W3C官方标准,是以层次结构组织的节点或信息片断的集合,允许在其中寻找特定信息。使用DOM解析XML文档结构需要加载整个XML文档,然后在内存中生成DOM树及树上的每个Node对象。由于它是基于信息层次的,因而DOM被认为是基于树或基于对象的,其优点如下。
(1)DOM树在内存中是持久的,应用程序能修改它以更改数据结构。
(2)任何时候都可以在DOM树中导航,而不是像SAX(Simple API for XML, XML简单应用程序接口)那样一次性处理。
(3)DOM使用起来要简单得多,不用花费大量编程时间在DOM应用上。
DOM的不足是如果使用DOM操作特别大的XML文档,解析和加载整个文档速度会很慢,甚至会耗尽内存资源。所以对于这种XML文档应使用其他方法来处理,如基于事件模型的SAX。
DOM接口
作为W3C的标准接口规范,DOM由3个部分组成,即核心(core)、HTML和XML。核心部分是结构化文档比较底层对象的集合,定义的对象已经完全可以表达出任何HTML和XML文档中的数据;HTML和XML接口两个部分则是专为操作具体的HTML和XML文档提供的高级接口,使处理这两类文档更加方便。
DOM接口规范中有如下4个基本接口。
(1)Document接口
Document接口从Node接口继承而来,是操作文档的入口,即整个文档的根节点。
该接口的常用属性有DocumentType类型的Doctype属性和Element类型的documentElement属性,它们分别用于记录文档的类型和访问文档的根元素。
该接口的常用方法如表1所示。
(2)Node接口
Node接口是Documet、Element、Attribute、Text及Comment等接口的父类,它是DOM树的基本数据类型,可以包含或不包含子节点。
该接口的常用方法如表2所示。
(3)NodeList接口NodeList接口是一个节点的集合,其中包含某个节点中的所有子节点,该集合中的所有项目都可以通过列表中的索引处理。NodeList接口的常用方法如表3所示。
如果item()方法的参数超出索引范围,则返回null。
NodeList对象是动态的,当文档内容改变时会自动更新该对象,而不用DOM应用程序重新获取它。
(4)NamedNodeMap接口
NamedNodeMap接口也是一个节点的集合,通过该接口可以像Map集合一样使用key/value键值对建立节点名和节点之间的映射关系,从而通过节点名直接访问特定的节点;另外在这个集合中,节点的排列是没有顺序的。
使用DOM读取XML文件
使用DOM操作XML需要创建DocumentBuilderFactory工厂,通过它来生成Document Builder的实例,该实例用于解析XML到Document对象中。
定义获取XML解析器的工厂对象的语法格式如下:
1 | DocumentBuilderFactory bdf=DocumentBuilderFactory.newInstance() |
创建DocumentBuilder对象解析XML文件的语法格式如下:
1 | DocumentBuilder db=dbf.newDocumentBuilder() |
从XML文件中解析Document对象的语法格式如下:
1 | Document doc=db.parse(String path) |
其中参数path是XML文件的路径信息。
从XML的标签名中获得所有属性值的语法格式如下:
1 | doc.getElementsByTagName(String tag) |
(1)tag:在XML文件中定义的标签信息。
(2)doc:Document类的实例对象。
SAX技术
SAX采用基于事件驱动的处理模式,将XML转换为事件,然后由事件处理器处理指定的事件。SAX之所以被称为“简单应用程序接口”,是因为SAX解析器只执行语法检查、字节流检查和触发事件等简单的工作。它采用顺序访问的机制,不能重新读取已经分析过的数据。这种处理的优点在于XML分析能够立即开始,而不是等待处理所有的数据。而且由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中,这对于大型文档来说是一个突出的优点。事实上,应用程序甚至不必解析整个文档,它可以在某个条件得到满足时停止解析。一般来说,SAX比DOM要快得多。
SAX编程
SAX和DOM均与具体的平台和语言无关,只是一个编程接口。在SAX编程时必须使用一个已经利用某种语言实现的SAX解析器,如Sun Microsystem的JAXP Java实现,它支持SAX和DOM两种解析器。
SAX常用接口
SAX提供的常用接口和类可以创建各种事件处理器、解析XML文档并处理SAX异常等功能。这些接口和类的说明如表4所示。
(1)DocumentHandler接口
在SAX编程中DocumentHandler用于接收XML文档的事件通知,它是最常用(也是最主要)的接口。当处理特定的XML文件时,需要创建一个实现该接口的类来处理每一个SAX事件,可以说这个接口实际上就是SAX处理XML文件的核心。该接口中的方法如表5所示。
(2)DTDHeadler接口
该接口负责接收DTD信息的相关事件,可以实现该接口处理DTD事件,其中的方法如表6所示。
(3)ErrorHandler接口
ErrorHandler是SAX错误处理器接口,主要用于定制SAX的错误处理。它替代了解析器的异常管理,其中的方法如表7所示。
(4)EntityResolver接口
实现EntityResolver接口的解析器可以解析XML文档包含的外部实体,该接口中包含的方法如下。
1 | resolveEntity(String publicId,String systemId) |
SAX解析XML文档的外部实体时调用该方法。
(5)Parser接口
Parser接口是SAX所有解析器都必须实现的重要接口,其中的parse()方法将被SAX程序调用以解析XML文档,该接口中的方法如表8所示。
(6)AttributeList接口
该接口是startElement事件获取的开始标记的属性列表,用于获取标记的所有属性,其中的方法如表9所示。
(7)Locator接口
解析器使用该接口在文档中定位,而且在报错时获取错误的位置,其中的方法如表10所示。
(8)HandlerBase类
HandlerBase类实现了DocumentHandler、DTDHandler、EntityResolver和ErrorHandler接口,并实现了其中的方法。它相当于这4个接口的适配器,可以继承这个适配器编写SAX的解析器,而不用编写所有4个接口方法的实现。
(9)InputSource类
InputSource类代表XML输入源,封装了XML的所有信息,解析器通过它获取XML文档的信息。该类中的方法如表11所示。
(10)SAXException类
SAXException类是SAX中所有异常的超类,封装了解析器的错误机制,该类中的方法如表12所示。
(11)SAXParseException类
这是SAX的另一个异常类,扩展了SAXException类并提供了更多的功能,该类中的方法如表13所示。
SAX实现方法
同DOM,使用SAX技术首先要创建SAX工厂类,由工厂类生成SAX解析器,然后由解析器调用parse()方法解析XML文件。parse()方法的两个参数分别是XML源(即XML文件的位置)和SAX的事件监听器。
(1)创建解析器
创建SAX解析器工厂实例的语法格式如下:
1 | SAXParserFactory spf=SAXParserFactory.newInstance() |
从工厂类中产生SAX解析器实例的语法格式如下:
1 | SAXParser sp=spf.newSAXParser() |
Spf为工厂类的实例对象。
解析指定XML文件内容的语法格式如下:
1 | sp.parse("XML/book.xml",bean) |
Sp:SAX解析器的实例对象,用来解析XML文档的内容。
bean:自定义SAX事件监听器的实例对象。
(2)事件处理
继承DefaultHandler类可以定制自己的SAX事件监听器,使用SAX解析XML文件的常用事件处理方法如下。
startDocument()方法:处理XML文档的开始事件,说明解析器开始解析文档,可以将解析文档之前需要做的工作放到其中。
语法格式如下:
1 | public void startDocument() throws SAXException{ |
startElement()方法:在解析器发现元素的起始标签时调用该方法。
语法格式如下:
1 | public void startElement(String namespaceURI,String localName,String qName,Attributes atts) throws SAXException{ |
该方法中的参数如表14所示。
characters()方法:在发现元素的起始标签之后由characters()监听方法处理元素的内容。
语法格式如下:
1 | public void characters(char[] ch,int start,int length) throws SAXException{ |
该方法中的参数如表15所示。
endElement()方法:在发现元素结束标签时激活此方法来完成元素读取后的操作。
语法格式如下:
1 | public void endElement(String namespaceURI,String localName,String qName) throws SAXException{ |
Qname为元素的名称。
endDocument()方法:XML文档的结束事件,可以在其中放置处理解析文档结束时的代码。
语法格式如下:
1 | public void endDocument(){ |