XML的解析与 DOM处理
22.2 XML的解析
若要处理XML文档,提取或修改其中的数据信息,就必须先对XML文档进行解析,从而识别出XML文档的结构和其中的数据。因此,就需要一些程序来对XML文件进行解析,并称这些程序为XML解析器。XML文档最基本的解析器有两种,分别是文档对象模型(Document Object Model简称DOM)和XML解析的简单API(SAX),这两者本质上都是一种Java的接口。
22.2.1 DOM处理
文档对象模型(Document Object Model简称DOM),是一种基于对象的API,使用DOM对XML文档进行解析时,会在内存中生成与XML文档内容对应的对象模型。当解析完成时,内存中会生成与XML文档结构对应的DOM对象树。这样便能够根据树的结构,以节点形式来对文档进行操作。
Java的JDK中包含了DOM分析器,在javax.xml.parsers包中,提供了DocumentBuilder类和DocumentBuilderFactory类。若要解析XML文档,可以采用如下步骤。
(1)需要一个DocumentBuilder类的对象(该对象可以使用DocumentBuilderFactory类的静态方法newInstance()来获取)。
(2)使用该对象中的parse()方法来解析XML文档。该过程就如同文件流的高级用法,首先需要建立File对象,用来将XML文档加载到内存中,之后使用DocumentBuilder对象中的parse()方法来解析这个XML文档。
(3)parse()方法将返回一个Document对象(Document类在org.w3c.dom包中),该对象正是XML文档所对应的树状结构,并保存在内存中。
使用Java程序解析XML文档“Demo.xml”的代码片断如下所示。
import java.io.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.*; //导入使用DOM解析XML文件的包
class ParseXML
{
……
public static void main(String args[])
{
//创建File的对象file,用来在内存中加载XML文件
File file = new File(“Demo.xml”);
//使用DocumentBuilderFactory类的静态方法newInstance(),来获取该类的一个对象factory
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//使用factory对象的newDocumentBuilder()方法,来获取DocumentBuilder类的对象
DocumentBuilder builder = factory.newDocumentBuilder();
//使用DocumentBuilder类对象的parse()方法来解析XML文件,并返回Document对象
Document doc = builder.parse(file);
……
}
}
通过上述代码,可以为所要解析的XML文件,创建一个Document对象doc,之后可以通过doc对象中的大量方法对XML文件实现各类操作,例如添加、删除、修改元素等。
代码22-5中,使用DOM解析器,实现对代码22-1中的XML文档进行解析,提取出两个“name”节点元素的内容。
代码22-5 使用DOM解析器实现对XML文档的解析XMLParse.java
import java.io.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.*;
import org.w3c.dom.CharacterData;
public class XMLParse
{
public static void main(String[] args)
{
//创建File的对象file,用来在内存中加载XML文件
File file = new File("C://Demo.xml");
//使用DocumentBuilderFactory类的静态方法newInstance(),来获取该类的一个对象factory
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try
{
//使用factory对象的newDocumentBuilder()方法,来获取DocumentBuilder类的对象
DocumentBuilder builder = factory.newDocumentBuilder();
//使用DocumentBuilder类对象的parse()方法,来解析XML文件,并返回Document对象
Document doc = builder.parse(file);
//使用doc对象的getDocumentElement()来获取根元素
Element element1 = doc.getDocumentElement();
//使用element对象的getNodeName()方法获取根元素的名字并显示出来
String str = element1.getNodeName();
System.out.println(str);
//使用根元素对象element1中的方法getElementsByTagName(),
//来获得其子元素名为"name"的一个列表list
NodeList list = element1.getElementsByTagName("name");
//使用getLength()方法获得该列表的长度
int n = list.getLength();
//通过循环,分别得到并显示元素名为"name"的元素内容
for (int i = 0; i < n; i++)
{
//获得列表中的每一个名为"name"的元素
Node node = list.item(i);
//获得该元素对应的内容
String value = node.getNodeValue();
System.out.println(value);
}
}catch(Exception e){}
}
}
代码编写好之后,需要将“Demo.xml”文件拷贝至“C:/”下后,再编译运行程序,程序运行结果如图22-4所示。
图22-4 程序运行结果
22.2.2 SAX处理
使用SAX同样可以完成对XML文档的解析,其对XML文件解析时,会生成相应的事件。与DOM不同的是,当使用DOM解析XML文档的时候,DOM程序会将整个XML文档都读入到一个树状结构中,并存储于内存。若遇到XML文档较大,并且只需要解析XML文档中一部分数据的时候,使用DOM解析器解析的速度就会明显变慢,效率很低。在这种情况下,可以选择使用SAX解析器。使用SAX解析器对XML文档进行解析时,程序会从XML文档开始位置起进行解析,同时根据已经定义好的事件处理器,来决定当前所解析的部分(元素、属性或时元素内容)是否有必要记录并存储。
在使用SAX解析器之前,首先要获得SAX解析器。在javax.xml.parsers包中,分别提供了SAXParser类和SAXParserFactory类,可以通过创建SAXParserFactory类的对象factory,并使用该对象的newSAXParser()方法来获取SAX解析器(saxParser),如下所示。
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
在获取了SAX解析器saxParser对象之后,就可以使用该对象的parse()方法来对XML文档进行解析,语法格式如下。
saxParser。Parse(source , handler);
其中,source参数可以是File类对象所指定的文件名及所在目录,也可以是URL字符串,同样也可以为一个输入流;handler参数则是DefaultHandler类的对象,其中的方法可以用于定义事件处理器。例如:
public void startElement(String namespace,String lname,String qname,Attributes att);
该方法就是DefaultHandler类的对象handler中,用于处理XML文档的一种方法,它包含4个参数,namespace参数用于描述元素的名字空间;lname参数用于描述元素本地名;qname参数用于描述元素名;att参数则是用来描述属性的。
SAX解析器的使用方法如下。
(1)事先规定事件处理的方法(包括遇到什么样元素该怎样处理等)。
(2)SAX解析器开始解析XML文档,当遇到每一个元素时,便会去查看之前定义的事件处理中(也就是DefaultHandler类的对象handler中),该元素是否符合被处理的条件,若符合则执行该方法,对元素进行相应处理;否则就跳过该元素,继续分析下面的每一个元素。
代码22-6中,使用SAX解析器,实现对代码22-4中的XML文档(Demo3.xml)进行解析,提取出包含属性的节点元素名称和内容。
代码22-6 使用SAX解析器实现对XML文档的解析SAXParseXML.java
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.Locator;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class SAXParseXML
{
public static void main(String[] args)
{
try
{
//用于创建SAXParserFactory类对象factory
SAXParserFactory factory = SAXParserFactory.newInstance();
//利用SAXParserFactory类对象factory的newSAXParser()方法,来获取SAX解析器
SAXParser saxParser = factory.newSAXParser();
//创建自定义事件处理类的对象
MyHandler myHandler = new MyHandler();
//使用SAX解析器对象中的parse()方法解析XML文档
saxParser.parse(new InputSource("c://Demo3.xml"),myHandler);
}
catch(SAXException e1){}
catch(Exception e2){}
}
}
class MyHandler extends DefaultHandler
{ //自定义事件处理类
public void startElement(String namespace,String lname,String qname,Attributes att)
{ //元素开始事件处理
if(att!=null) //当元素的属性不为空值时触发事件处理
{
for (int i = 0; i < att.getLength(); i++)
{
//用于获取该元素的名称
System.out.println("元素名为:"+qname);
if(att.getQName(i).equals("edition"))
{
//用于获取"edition"属性的名称和属性值
System.out.print("属性名为:"+att.getQName(i));
System.out.println(",属性值为:"+att.getValue(i));
}
if(att.getQName(i).equals("isbn"))
{
//用于获取"isbn"属性的名称和属性值
System.out.print("属性名为:"+att.getQName(i));
System.out.println(",属性值为:"+att.getValue(i));
}
}
}
}
}
代码编写好之后,需要将“Demo3.xml”文件拷贝至“C:/”下后,再编译运行程序,程序运行结果如图22-5所示。
图22-5 程序运行结果