Sax快速入门

来源:互联网 发布:婚庆音响设备数据 编辑:程序博客网 时间:2024/05/17 23:59

一、本教程旨在为希望运用SAX的Java程序员提供一份快速入门的教程。

二、基本的环境

Sax是一个用于各种各样的XML解析器(或者其他可以看做XML解析器的解析器)通用接口的实现,就像JDBC作为一个能供许多关系型

数据库的通用驱动的一样。如果你想用SAX,你需用如下的几样东西:

a. Java 1.1或更高版本

b. 一个能兼用SAX2(总共有这么几个版本:SAX2M,2001-11-12; SAX 2.0.1, 2002-1-29, SAX2.0.2, 2004-4-24)的XML解析器被安装

在你的Java classpath中

c. SAX2被安装在你的java classpath中(貌似Jdk已经集成了吧?)

大多数的Java/XML工具包括SAX2 和 XML解析器都用到SAX。大多数的web应用服务器也把它最为XML support的核心。特别强调的是,

JAXP 1.1 支持SAX2.

三、XML的解析

我们从创建DefaultHandler的一个子类开始:

import org.xml.sax.helpers.DefaultHandler;public class MySAXApp extends DefaultHandler{    public MySAXApp ()    {super();    }}

因为这是一个Java程序,我们将会创建一个Main方法来调用XMLReaderFactory 的createXMLReader方法来动态地选择一个SAX

驱动。注意了,在这里,我们只用了“throws Exception”,在真正的应用程序中,将会有容错处理:

 public static void main (String args[])throws Exception    {XMLReader xr = XMLReaderFactory.createXMLReader();    }

可能在你的Java环境中还没有整合默认的编译路径(或者可能是META-INF/services/org.xl.sax.driver system resource),

那么你需要去为SAX driver设置 org.xml.sax.dirve 的Java 系统属性, 比如

java -Dorg.xml.sax.driver=com.example.xml.SAXDriver MySAXApp sample.xml下面是击中SAX2的驱动,它们的class names和相关信息如下:

Class NameNotesgnu.xml.aelfred2.SAXDriverLightweight non-validating parser; Free Softwaregnu.xml.aelfred2.XmlReaderOptionally validates; Free Softwareoracle.xml.parser.v2.SAXParserOptionally validates; proprietaryorg.apache.crimson.parser.XMLReaderImplOptionally validates; used in JDK 1.4; Open Sourceorg.apache.xerces.parsers.SAXParserOptionally validates; Open Source


或者,如果你不想在你的程序中使用指定的Sax drive, 你也可以直接用它的构造器。我们假设你的XML解析器叫做com.example.xml.SAXDriver,

这实际上可能不存在。你必须知道要知道用于解析的那个真正driver的名字,这样,可能进行如下操作:

public static void main (String args[])throws Exception    {XMLReader xr = new com.example.xml.SAXDriver();    }
我们用xr这个对象去解析XML文档,但是,我们必须先去注册一个事件handlers,以便于解析器用来report信息,从XMLReader中调用setConentHandler 和

setErrorHandler方法,在一个实际程序的应用中,这个hanlders通常要做成一个独立的对象,但是在这里,只是为了演示,我们把handlers绑定

在了最顶层的类中(即main方法所在的类),这样,我们必须去实例化这个顶层类并且为XML Reader这个解析器注册hanlders:

public static void main (String args[])throws Exception    {XMLReader xr = XMLReaderFactory.createXMLReader();MySAXApp handler = new MySAXApp();xr.setContentHandler(handler);xr.setErrorHandler(handler);    }

上面的代码创建了MySAXApp的一个实例去接受XML解析事件,并且把常规的content 事件和error 事件处理器注册到这个解析器上。

现在,就让我们来开始解析吧。

public static void main (String args[])throws Exception    {XMLReader xr = XMLReaderFactory.createXMLReader();MySAXApp handler = new MySAXApp();xr.setContentHandler(handler);xr.setErrorHandler(handler);// Parse each file provided on the// command line.for (int i = 0; i < args.length; i++) {    FileReader r = new FileReader(args[i]);    xr.parse(new InputSource(r));}    }

值得注意的是,每一个reader必须被包装成一个inputSource而被解析。以下是到目前为止这个demo的整个代码:

import java.io.FileReader;import org.xml.sax.XMLReader;import org.xml.sax.InputSource;import org.xml.sax.helpers.XMLReaderFactory;import org.xml.sax.helpers.DefaultHandler;public class MySAXApp extends DefaultHandler{    public static void main (String args[])throws Exception    {XMLReader xr = XMLReaderFactory.createXMLReader();MySAXApp handler = new MySAXApp();xr.setContentHandler(handler);xr.setErrorHandler(handler);// Parse each file provided on the// command line.for (int i = 0; i < args.length; i++) {    FileReader r = new FileReader(args[i]);    xr.parse(new InputSource(r));}    }    public MySAXApp ()    {super();    }}
你可以编译上述代码并且运行它。(需要确保的一点是,你因该在org.xml.sax.dirver property 文件中定义这个Sax driver class),如果

被解析的文档不是畸形的,这个程序将啥也不会出现(畸形的xml的话,会抛xml结构异常信息)。这是因为你还没为这个应用程序set up处理事件。

处理事件

当你开始去为XML解析实现响应方法时,这就会变得越来越有趣了。其中最重要的响应事件某过于文档的开始和结束,元素的开始和结束,字符数据

的处理。

为了找出document的start和end,这个应用程序必须实现startDocument和endDocument这两个方法:

 public void startDocument ()    {System.out.println("Start document");    }    public void endDocument ()    {System.out.println("End document");    }

这个start/endDocument 的event handler没有参数。当Sax driver一旦到达document的开头的时候,它会调用startDocument方法,一但到达结尾时,它会调用endDocument方法(即使这个文档存在一些错误)。

这个demo只是简单地输出了一些消息,但是,你的程序也可以在这个handler里增加任何你想要的代码。通常地,这些被增加的代码回去做

下面的几件事情:在momery中生成一些dom 树,输出,整合到database中,或者从XML stream中提取信息。

Sax driver将会通过同document一样的方式标志一个元素的start和end,这两个方法中会用一些参数被传递过来:

 public void startElement (String uri, String name,      String qName, Attributes atts)    {if ("".equals (uri))    System.out.println("Start element: " + qName);else    System.out.println("Start element: {" + uri + "}" + name);    }    public void endElement (String uri, String name, String qName)    {if ("".equals (uri))    System.out.println("End element: " + qName);else    System.out.println("End element:   {" + uri + "}" + name);    }

这个方法每次在遇到element start和end的时候,如果这个元素的namespace存在,它将会输出namespace和localname如果不存在namespace,

它将会输出它将会输出qName(qualified Name, 参考qName).

最后,SAX2通过characters这个方法显示一些常规的字符串数据。在下面的实现中,将会输出所有的字符数据(标签的文本数据)。代码可能有一点长

因为要编译一些特殊的字符:

public void characters (char ch[], int start, int length)    {System.out.print("Characters:    \"");for (int i = start; i < start + length; i++) {    switch (ch[i]) {    case '\\':System.out.print("\\\\");break;    case '"':System.out.print("\\\"");break;    case '\n':System.out.print("\\n");break;    case '\r':System.out.print("\\r");break;    case '\t':System.out.print("\\t");break;    default:System.out.print(ch[i]);break;    }}System.out.print("\"\n");    }

注意,因为SAX driver可以随意获取它想要的任意字符数据块,所以你不可能仅通过一个简单的characters事件就能计算出这个element的所有字符信息。

一下是关于characters的一个具体例子:

package com.aug.desmond.sax.start.test;import java.io.FileReader;import org.xml.sax.Attributes;import org.xml.sax.InputSource;import org.xml.sax.SAXException;import org.xml.sax.XMLReader;import org.xml.sax.helpers.DefaultHandler;import org.xml.sax.helpers.XMLReaderFactory;import static com.aug.desmond.util.Print.*;public class MySAXApp extends DefaultHandler {public static void main(String[] args) throws Exception{XMLReader xr = XMLReaderFactory.createXMLReader();MySAXApp handler = new MySAXApp();xr.setContentHandler(handler);xr.setErrorHandler(handler);for(int i=0; i<args.length; i++) {FileReader r = new FileReader(args[i]);xr.parse(new InputSource(r));}}@Overridepublic void characters(char ch[], int start, int length) throws SAXException {print(new String(ch, start, length));}@Overridepublic void endElement(String uri, String localName, String qName)throws SAXException {print("[end element] "+uri+","+localName+","+qName);}@Overridepublic void startElement(String uri, String localName,      String qName, Attributes attributes) throws SAXException {print("[start element] "+uri+","+localName+","+qName);}public MySAXApp() {super();}}
XML文件:

<?xml version="1.0" encoding="UTF-8" ?><root><head/><body>world</body>out_of_tag_after_body<Chinese>China</Chinese></root>

输出的结果为:

[start element] ,root,root[start element] ,head,head[end element] ,head,head[start element] ,body,bodyworld[end element] ,body,bodyout_of_tag_after_body[start element] ,Chinese,ChineseChina[end element] ,Chinese,Chinese[end element] ,root,root

可以看出,
out_of_tag_after_body 在元素body 和Chinese之间,它也能够被Characters方法读出来,也就是说,Characters方法读的是tag之外的所有字符数据,
比如<a/><b/> 元素a,b之间即使没有数据,Characters也回去读它,只不过是空字符串而已。

Sax2的应用示例

下面是这个demo的全部代码:

import java.io.FileReader;import org.xml.sax.XMLReader;import org.xml.sax.Attributes;import org.xml.sax.InputSource;import org.xml.sax.helpers.XMLReaderFactory;import org.xml.sax.helpers.DefaultHandler;public class MySAXApp extends DefaultHandler{    public static void main (String args[])throws Exception    {XMLReader xr = XMLReaderFactory.createXMLReader();MySAXApp handler = new MySAXApp();xr.setContentHandler(handler);xr.setErrorHandler(handler);// Parse each file provided on the// command line.for (int i = 0; i < args.length; i++) {    FileReader r = new FileReader(args[i]);    xr.parse(new InputSource(r));}    }    public MySAXApp ()    {super();    }    ////////////////////////////////////////////////////////////////////    // Event handlers.    ////////////////////////////////////////////////////////////////////    public void startDocument ()    {System.out.println("Start document");    }    public void endDocument ()    {System.out.println("End document");    }    public void startElement (String uri, String name,      String qName, Attributes atts)    {if ("".equals (uri))    System.out.println("Start element: " + qName);else    System.out.println("Start element: {" + uri + "}" + name);    }    public void endElement (String uri, String name, String qName)    {if ("".equals (uri))    System.out.println("End element: " + qName);else    System.out.println("End element:   {" + uri + "}" + name);    }    public void characters (char ch[], int start, int length)    {System.out.print("Characters:    \"");for (int i = start; i < start + length; i++) {    switch (ch[i]) {    case '\\':System.out.print("\\\\");break;    case '"':System.out.print("\\\"");break;    case '\n':System.out.print("\\n");break;    case '\r':System.out.print("\\r");break;    case '\t':System.out.print("\\t");break;    default:System.out.print(ch[i]);break;    }}System.out.print("\"\n");    }}
输出

用到了如下的XML:

?xml version="1.0"?><poem xmlns="http://www.megginson.com/ns/exp/poetry"><title>Roses are Red</title><l>Roses are red,</l><l>Violets are blue;</l><l>Sugar is sweet,</l><l>And I love you.</l></poem>

如果这个文档的名字叫做roses.xml并且在你的classpath中有一个叫 com.example.xml.SAXDriver(这个driver实际上并不存在)的SAX2 driver,你可以通过如下的方式去 

运行它:

java -Dorg.xml.sax.driver=com.example.xml.SAXDriver MySAXApp roses.xml
输出结果如下:

Start documentStart element: {http://www.megginson.com/ns/exp/poetry}poemCharacters:    "\n"Start element: {http://www.megginson.com/ns/exp/poetry}titleCharacters:    "Roses are Red"End element:   {http://www.megginson.com/ns/exp/poetry}titleCharacters:    "\n"Start element: {http://www.megginson.com/ns/exp/poetry}lCharacters:    "Roses are red,"End element:   {http://www.megginson.com/ns/exp/poetry}lCharacters:    "\n"Start element: {http://www.megginson.com/ns/exp/poetry}lCharacters:    "Violets are blue;"End element:   {http://www.megginson.com/ns/exp/poetry}lCharacters:    "\n"Start element: {http://www.megginson.com/ns/exp/poetry}lCharacters:    "Sugar is sweet,"End element:   {http://www.megginson.com/ns/exp/poetry}lCharacters:    "\n"Start element: {http://www.megginson.com/ns/exp/poetry}lCharacters:    "And I love you."End element:   {http://www.megginson.com/ns/exp/poetry}lCharacters:    "\n"End element:   {http://www.megginson.com/ns/exp/poetry}poemEnd document

如果这个roses.xml没有包含 xmlns="http://www.megginson.com/ns/exp/poetry" 这个名空间属性去申明所有的元素将都在这个名空间下,那么,就会有以下形式的输出:

Start documentStart element: poemCharacters:    "\n"Start element: titleCharacters:    "Roses are Red"End element:   titleCharacters:    "\n"Start element: lCharacters:    "Roses are red,"End element:   lCharacters:    "\n"Start element: lCharacters:    "Violets are blue;"End element:   lCharacters:    "\n"Start element: lCharacters:    "Sugar is sweet,"End element:   lCharacters:    "\n"Start element: lCharacters:    "And I love you."End element:   lCharacters:    "\n"End element:   poemEnd document

你可能用到这两种类型的document:一种用了namespace,另一种没有。对于element(或attributes),也存在同样的情况。因此,要具体情况

具体分析以便写出合适的code。

Element 的Attributes

element的attributes也可以有namespace,用法和element的一样。下面是一个demo:

XML:

<?xml version="1.0" encoding="UTF-8" ?><root xmlns="http://www.desmond.com" xmlns:attr="https://www.presley.com"><head hd="hd" isHead="true"/><body attr:bd="bd">world</body><Chinese cn="cn" zone="8">China</Chinese></root>

Code:

package com.aug.desmond.sax.start.test;import java.io.FileReader;import org.xml.sax.Attributes;import org.xml.sax.InputSource;import org.xml.sax.SAXException;import org.xml.sax.XMLReader;import org.xml.sax.helpers.DefaultHandler;import org.xml.sax.helpers.XMLReaderFactory;import static com.aug.desmond.util.Print.*;public class MySAXApp extends DefaultHandler {public static void main(String[] args) throws Exception{XMLReader xr = XMLReaderFactory.createXMLReader();MySAXApp handler = new MySAXApp();xr.setContentHandler(handler);xr.setErrorHandler(handler);for(int i=0; i<args.length; i++) {FileReader r = new FileReader(args[i]);xr.parse(new InputSource(r));}}@Overridepublic void startElement(String uri, String localName,String qName, Attributes attributes) throws SAXException {print("[element] uri="+uri+", localName="+localName);print("length of attributes=" + attributes.getLength());// get info of each attributefor(int i = 0; i < attributes.getLength(); i++) {System.out.print("[uri="+ attributes.getURI(i)+ ",qName=" + attributes.getQName(i) + ",localName=" + attributes.getLocalName(i) + ", type=" + attributes.getType(i)+ ",value=" + attributes.getValue(i) + "]");}// get attribute by qNameprint("zone="+attributes.getValue("zone"));print("bd="+attributes.getValue("attr:bd"));// get attribute by uri, localNameprint("bd="+attributes.getValue("https://www.presley.com", "bd"));print("*************************");}public MySAXApp() {super();}}

Output:

[element] uri=http://www.desmond.com, localName=rootlength of attributes=0zone=nullbd=nullbd=null*************************[element] uri=http://www.desmond.com, localName=headlength of attributes=2[uri=,qName=hd,localName=hd, type=CDATA,value=hd][uri=,qName=isHead,localName=isHead, type=CDATA,value=true]zone=nullbd=nullbd=null*************************[element] uri=http://www.desmond.com, localName=bodylength of attributes=1[uri=https://www.presley.com,qName=attr:bd,localName=bd, type=CDATA,value=bd]zone=nullbd=bdbd=bd*************************[element] uri=http://www.desmond.com, localName=Chineselength of attributes=2[uri=,qName=cn,localName=cn, type=CDATA,value=cn][uri=,qName=zone,localName=zone, type=CDATA,value=8]zone=8bd=nullbd=null*************************

来自:http://www.saxproject.org/quickstart.html