XML文件解析技术总结(二)

来源:互联网 发布:淘宝直播怎么打开 编辑:程序博客网 时间:2024/04/28 05:25

XML文件解析技术总结(二)

在上一篇文章中我们主要是简单的介绍了一下XML和相关的解析技术,接下来我们就来相对具体地介绍一下解析器模型。

DOM

DOMW3C组织以IDLInterface Definition Language, 接口定义语言)的形式定义了DOM中的接口。某种语言要实现DOM,需要将DOM接口转换为本语言中的适当结构。

DOM结构模型

DOM中的核心概念是节点,它把XML文档的各个部分(元素、属性、文本、注释和处理指令等)都抽象为节点。在内存中整个文档是一个树的结构存储的,整棵树是个节点,树中的每一个节点也是一个树。我们通过访问树中的节点来存取XML文档的内容。

DOM定义了一个Node接口,用于表示文档树中一个节点。从Node接口派生出了更多的具体接口,例如Document接口、Element接口、Attr接口。

上图表示DOM中表示XML文档中各组成部分的接口继承关系

 

在实际使用中,很少使用Node对象,而是DocumentTextElementAttrNode对象的子对象来操作文档。当然在顶层的Node接口声明了对节点进行操作的方法。下面就列出了Node接口的主要方法:

public String getNodeName();

       返回该节点的名字

public short getNodeType();

       返回表示该节点类型的代码

public String getNodeValue() throws DOMException;

       返回该节点的值

public void setNodeValue(String nodeValue) throws DOMException;

       设置该节点的值

public boolean hasChildNodes();

       判断该节点是否还有子节点

public NodeList getChildNodes();

       以列表的形式返回该节点的所有子节点

………等等

DOM解析器工厂

javax.xml.parsers包中定义了DOM解析器工厂类DocumentBuildFactory,用于产生DOM解析器。DocumentBuildFactory是一个抽象类,在这个类中提供了一个静态的方法newInstance( ),用于创建工厂类的一个实例。

DocumentBuildFactory factory = DocumentBuildFactory.newInstance();

DoucmentBuild build = factory.newDocumentBuilder();                                        

DocumentBuild类也是一个抽象类,调用DocumentBuildFactorynewInstance( )方法得到具体厂商的工厂类的实例后,再利用其newDocumentBuilder( )方法,得到具体厂商的DOM解析器对象。

DocumentBuilder类提供了parse()方法,用于解析XML文档的内容,返回一个表示整个文档的Document对象。Parse()方法的参数可以是File类、InputSource类、InputStream类或表示XML文件的URI

DOM树中的节点类型

DOM本质上是节点的集合。由于一个文档中可能包含不同类型的信息。

节点类型

DOM中的接口

说明

注释

Comment

Comment接口继承自CharacterData接口,表示注释的内容

处理指令

ProcessingInstruction

ProcessingInstruction接口表示XML文档中的处理指令部分

文档类型

DocumentType

每一个Document都有一个docType属性,其值是null或是DocumentType对象。DocumentType接口为DTD中声明的实体列表和记号(notation)提供了一个接口

文档片断

DocuementFragment

文档其实是“最小”的Document对象。DocumentFragment对象和Document对象的主要区别是,DocumentFragment可以不是格式良好的。可以通过移动文档的片断来重新排列文档。

CDATA

CDATASection

CDATASection接口继承自Text接口,表示XML文档的CDATA

实体

Entity

Entity接口表示一个在XML文档中已分析的或未分析的实体。

实体引用

EntityReference

EntityReference节点可以用于表示DOM树中的一个实体引用。

记号

Notation

Notation接口表示了在DTD中声明的记号

例子

package org.jackkp.dom;

 

import java.io.File;

import java.io.IOException;

 

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

 

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.Node;

import org.w3c.dom.NodeList;

import org.xml.sax.SAXException;

 

public class DOMTest {

    public static void main(String[] args){

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

       try{

           DocumentBuilder db = dbf.newDocumentBuilder();

           File file = new File("student.xml");

           Document doc = db.parse(file);

          

           NodeList nl = doc.getElementsByTagName("student");

           for(int i = 0; i < nl.getLength(); i++){

              Element stu = (Element)nl.item(i);

              Node name = stu.getElementsByTagName("name").item(0);

              Node age = stu.getElementsByTagName("age").item(0);

             

              System.out.print("姓名:  ");

              System.out.println(name.getFirstChild().getNodeValue());

              System.out.print("年龄:  ");

              System.out.println(age.getFirstChild().getNodeValue());

              System.out.println("****************************");

           }

          

       }catch(ParserConfigurationException e){

           e.printStackTrace();

       }catch(IOException e){

           e.printStackTrace();

       }catch(SAXException e){

           e.printStackTrace();

       }

    }

}

下面是运行结果:

SAX

在使用DOM解析XML文档是,需要读入整个XML文档,然后在内存中创建DOM树,生成DOM树上的每个节点对象。只有在整个DOM树创建完成后,才能进行其它的操作。当XML文档比较大时,构建DOM树将花费大量的时间和内存。

而使用SAX允许你在读取文档的时候对它进行处理。

SAX处理机制

SAX是一种基于事件驱动的API。用SAX模型来解析XML文档时,要涉及到解析器和事件处理器。解析器负责读取XML文档,并向事件处理器发送请求;而事件处理器负责对事件作出响应,对传递的XML数据进行处理。

SAX在解析文档时,一般会依次产生下列事件:

文档开始

       元素开始

              字符数据(可能是XML文档中的空白部分)

              元素开始

                     字符数据

              元素结束

              字符数据

       元素结束

文档结束

事件处理器中对事件做出响应的方法也叫做回调方法(callback method)。

解析器

XMLReaderSAX2.0解析器必须实现的接口,这个接口允许应用程序设置和查询解析器的功能和特性,可以注册用户自定义的事件处理器,以及文档的解析。XMLReader接口中的主要方法如下:

 

void setEntityResolver(EntityResolver resolver):允许应用程序注册一个实体解析器。如果应用程序没有注册实体解析器,XMLReader将执行它自己的默认实体解析器。

EntityResolver getEntityResolver( ):返回当前的实体解析器。

void setContentHandler(ContentHandler handler):允许应用程序注册一个内容事件处理器。如果应用程序没有注册内容事件处理器,那么SAX解析器报告的所有内容事件都将被忽略。

ContentHandler getHandler( ):返回当前的内容处理器。

void parse(InputSource input) throws IOException, SAXException

void parse(String systemId) throws IOException, SAXException

parse( )方法用于解析XML文档。应用程序可以使用这个方法来通知XMLReader开始解析从任何有效的输入源(URI、字节流或字符流)读取的XML文档。在解析过程中XMLReader通过注册的事件处理器来提供XML文档的信息。

事件解析器

解析器提供商负责提供实现XMLReader接口的解析器类,用户只需编写事件处理器程序即可。ContentHandler接口是一个主要的处理器接口。如果应用程序要获得基本的解析事件,它就要实现这个接口,并使用XMLReader对象的setContentHandler()方法向解析器注册一个ContentHandler实例。解析器使用这个实例来报告与文档相关的基本事件。ContentHandler( )的主要方法如下:

 

void setDocumentLocation(Locator locator):接收一个获取文档分析时产生的SAX事件对象定位信息的对象。该方法将在解析器报告任何其它文档事件之前被调用。定位器对象允许应用程序测试任何与文档相关的事件的结束位置。

void startDocument( ) throws SAXException;

void endDocument( ) throws SAXException;

void startElement(String uri, String localName, String qName, Attributes atts) throws SAXExceptionXML文档的每一个元素开始时调用这个方法。startElement()方法的参数取决于SAX本身的http://xml.org/sax/features/namspaceshttp://xml.org/sax/features/namespace-prefixs属性值

l        namespaces属性值是true时,名称空间(uri)和本地名(localName)是必需的。为false时,两者是可选的(默认是true

l        namespace-prefixes属性值是true,那么限定名是必需的,否则是可选的(默认是false)。

void endElement(String uri, String localName, String qName) throws SAXException:解析器在XML文档的每一个元素结束时调用这个方法。

void processingInstruction(String arget, String data) throws SAXException:解析器每遇到一个处理指令就调用这个方法。

 

JAXP也为SAX解析器提供了工厂类——SAXParserFactory类。SAX解析器工厂类的实例与DOM解析器工厂类的实例类似,都是通过newInstance( )方法来创建的。JAXP中定义的SAX解析器类是SAXParser(相当于DOM中的DocumentBuilder类,获取方法也类似)。实际上SAXParserJAXPXMLReader实现类的一个包装类。在SAXParser中定义了返回XMLReader实例的方法getXMLReader( )

public abstract XMLReader getXMLReader( );

XMLReaderSAXParser中都有parse( )方法,并且是等效的。但SAXParser中的parse( )方法使用范围更广,因为它能接受更多的参数,对不同的XML文档数据源进行解析。

public void parse(InputSource is, DefaultHandler dh) throws SAXException, IOException

public void parse(InputStream is, DefaultHandler dh, String systemId) throws SAXException, IOException

public void parse(String uri, DefaultHandler dh) throws SAXException, IOException

public void parse(File f, DefaultHandler dh) throws SAXException, IOException

public void parse(InputSource is, DefaultHandler dh) throws SAXExcepiton, IOException

例子

package org.jackkp.sax;

 

import java.io.File;

import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;

import javax.xml.parsers.SAXParser;

import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;

import org.xml.sax.SAXException;

import org.xml.sax.helpers.DefaultHandler;

 

public class SAXParserTest extends DefaultHandler{

 

    public void startDocument() throws SAXException{

       System.out.println("This is the starting of the document");

       System.out.println("<?xml version='1.0' encoding='GB2312'?>");

    }

    public void processingInstruction(String target, String data)

           throws SAXException{

       System.out.println("Processing the instructions");

       System.out.println("<?" + target + " " + data +"?>");

    }

    public void startElement(String uri,

           String localname,

           String qName,

           Attributes attrs) throws SAXException{

       System.out.println("Output the tabs and their attributes");

       System.out.print("<" + qName);

       int length = attrs.getLength();

       for (int i = 0; i < length; i++) {

           System.out.print(" ");

           System.out.print(attrs.getQName(i));

           System.out.print(attrs.getValue(i));

           System.out.print("/"");

       }

       System.out.println(">");

    }

   

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

           throws SAXException{

       //输出元素的数据内容

       System.out.println(new String(ch, start, length));

    }

    public void endElement(String uri, String localName, String qName)

           throws SAXException{

       //输出元素的结束标签

       System.out.println("</" + qName + ">");

    }

   

    public static void main(String[] args) {

       SAXParserFactory  spf = SAXParserFactory.newInstance();

       SAXParser sp = null;

       try{

           sp = spf.newSAXParser();

           File file = new File("student.xml");

           sp.parse(file, new SAXParserTest());

          

        }catch(ParserConfigurationException e){

           e.printStackTrace();

       }catch(SAXException e){

           e.printStackTrace();

       }catch(IOException e){

           e.printStackTrace();

       }

    }

}

下面是这个程序的运行结果:

 

 
原创粉丝点击