Tomcat中xml的解析器Digester 第一篇(共三篇)

Tomcat中server.xml定义了进行服务器的配置, 如JNDI, 最大线程数, 监听端口等。 Tomcat在启动的时候就利用server.xml中的配置初始化Service,Server,Engine,Host。

Tomcat利用的是Digester, Digester其实原来是struts的一个模块, 后来发现这个xml转Java Object费用有实用性, 于是成为apache的一个common模块。 Tomcat取了Digester中的接口和几个普遍性Rule,并且自己实现了一些Rule.


本文先分析如何使用SAX进行XML转Java, 然后再利用Digester进行XML解析,最后分析Tomcat中的Rule使用。

文章代码比较多, 分三篇。
第一篇分析SAX进行XML转Java; 第二篇利用Digester进行XML解析; 第三篇析Tomcat中的Rule使用。

数据绑定概念:
[b]编组[/b]([i]Marshalling[/i])是把内存中的数据转化到存储媒介上的过程。因此在 Java 和 XML 环境中,编组就是把一些 Java 对象转化成一个(或多个) XML 文档。在数据库环境中,则是把 Java 表示的数据存入数据库。显然,编组的秘密在于把 Java 实例中的面向对象结构转化成适用于 XML 的 扁平结构,或者 RDBMS 中的关系结构(使用 Java 技术转换到 OODBMS 实际上很简单)。

[b]解组[/b]([i]Unmarshalling[/i])是把数据从存储媒介转换到内存中的过程--正好与编组相反。因此需要把 XML 文档解组到 Java VM 中。这里的复杂性不是在扁平数据中,因为这不是必需的,而在于从正确的数据到正确的 Java 代码变量的映射。如果映射是错误的,就不可能正确地访问数据。当然,如果再尝试重新编组还会造成更大的问题,并且问题传播得很快。

1. Sax Unmarshaller

SAX(the Simple API for XML)是DOM文档驱动的解析器, 它顺序读取文档并且触发相应的Callback事件。Callback事件有元素开始事件,元素结束事件等。接口org.xml.sax.ContentHandler定义了每个SAX事件, 开发人员有时候不关心所有的事件,可以使用默认的DefaultHandler。

接下来分析如何利用SAX把XML转成Java Object。
为了简单起见, 不定义DTD文件。

例子定义了目录,书本, 杂志和文章类。

首先定义catalog.xml文件
[code]
<?xml version="1.0"?>

<catalog library="somewhere">

<book>
<author>Author 1</author>
<title>Title 1</title>
</book>

<book>
<author>Author 2</author>
<title>His One Book</title>
</book>

<magazine>
<name>Mag Title 1</name>
<article page="5">
<headline>Some Headline</headline>
</article>
<article page="9">
<headline>Another Headline</headline>
</article>
</magazine>

<book>
<author>Author 2</author>
<title>His Other Book</title>
</book>

<magazine>
<name>Mag Title 2</name>

<article page="17">
<headline>Second Headline</headline>
</article>
</magazine>

</catalog>

[/code]

Catalog.java

[code]
package benewu.gmail.study.tomcat.digester;

import java.util.Vector;

public class Catalog {
private Vector books;
private Vector magazines;

public Catalog() {
books = new Vector();
magazines = new Vector();
}

public void addBook( Book rhs ) {
books.addElement( rhs );
}
public void addMagazine( Magazine rhs ) {
magazines.addElement( rhs );
}

public String toString() {
String newline = System.getProperty( "line.separator" );
StringBuffer buf = new StringBuffer();

buf.append( "--- Books ---" ).append( newline );
for( int i=0; i<books.size(); i++ ){
buf.append( books.elementAt(i) ).append( newline );
}

buf.append( "--- Magazines ---" ).append( newline );
for( int i=0; i<magazines.size(); i++ ){
buf.append( magazines.elementAt(i) ).append( newline );
}

return buf.toString();
}
}

[/code]

Book.java
[code]
package benewu.gmail.study.tomcat.digester;

public class Book {
private String author;
private String title;

public Book() {}

public void setAuthor( String rhs ) { author = rhs; }
public void setTitle( String rhs ) { title = rhs; }

public String toString() {
return "Book: Author='" + author + "' Title='" + title + "'";
}
}
[/code]

Magazine.java
[code]
package benewu.gmail.study.tomcat.digester;

import java.util.Vector;

public class Magazine {
private String name;
private Vector articles;

public Magazine() {
articles = new Vector();
}

public void setName( String rhs ) { name = rhs; }

public void addArticle( Article a ) {
articles.addElement( a );
}

public String toString() {
StringBuffer buf = new StringBuffer( "Magazine: Name='" + name + "' ");
for( int i=0; i<articles.size(); i++ ){
buf.append( articles.elementAt(i).toString() );
}
return buf.toString();
}
}

[/code]

Article.java
[code]
package benewu.gmail.study.tomcat.digester;

public class Article {
private String headline;
private String page;

public Article() {}

public void setHeadline( String rhs ) { headline = rhs; }
public void setPage( String rhs ) { page = rhs; }

public String toString() {
return "Article: Headline='" + headline + "' on page='" + page + "' ";
}
}
[/code]


定义好了类和对应的xml配置, 开始利用catalog.xml进行初始化Catalog吧。

SaxCatalogUnmarshaller继承DefaultHandler, 重写关键的两个分方法:startElement和endElement

SaxCatalogUnmarshaller,java

[code]
package benewu.gmail.study.tomcat.digester.unmarshalling;

import java.util.Stack;

import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.helpers.DefaultHandler;

import benewu.gmail.study.tomcat.digester.Article;
import benewu.gmail.study.tomcat.digester.Book;
import benewu.gmail.study.tomcat.digester.Catalog;
import benewu.gmail.study.tomcat.digester.Magazine;

class SaxCatalogUnmarshaller extends DefaultHandler {
private Catalog catalog;

private Stack stack;
private boolean isStackReadyForText;

private Locator locator;

// -----

public SaxCatalogUnmarshaller() {
stack = new Stack();
isStackReadyForText = false;
}

public Catalog getCatalog() { return catalog; }

// ----- callbacks: -----

public void setDocumentLocator( Locator rhs ) { locator = rhs; }

// -----

/**
* the [namespace URI], the local name, and the fully [qualified name] of the element.
*/
public void startElement( String uri, String localName, String qName,
Attributes attribs ) {

isStackReadyForText = false;

// if next element is complex, push a new instance on the stack
// if element has attributes, set them in the new instance
if( localName.equals( "catalog" ) ) {
stack.push( new Catalog() );

}else if( localName.equals( "book" ) ) {
stack.push( new Book() );

}else if( localName.equals( "magazine" ) ) {
stack.push( new Magazine() );

}else if( localName.equals( "article" ) ) {
stack.push( new Article() );

String tmp = resolveAttrib( uri, "page", attribs, "unknown" );
((Article)stack.peek()).setPage( tmp );
}
// if next element is simple, push StringBuffer
// this makes the stack ready to accept character text
else if( localName.equals( "title" ) || localName.equals( "author" ) ||
localName.equals( "name" ) || localName.equals( "headline" ) ) {
stack.push( new StringBuffer() );
isStackReadyForText = true;
}
// if none of the above, it is an unexpected element
else{
// do nothing
}
}

// -----


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

// recognized text is always content of an element
// when the element closes, no more text should be expected
isStackReadyForText = false;

// pop stack and add to 'parent' element, which is next on the stack
// important to pop stack first, then peek at top element!
Object tmp = stack.pop();

if( localName.equals( "catalog" ) ) {
catalog = (Catalog)tmp;

}else if( localName.equals( "book" ) ) {
((Catalog)stack.peek()).addBook( (Book)tmp );

}else if( localName.equals( "magazine" ) ) {
((Catalog)stack.peek()).addMagazine( (Magazine)tmp );

}else if( localName.equals( "article" ) ) {
((Magazine)stack.peek()).addArticle( (Article)tmp );
}
// for simple elements, pop StringBuffer and convert to String
else if( localName.equals( "title" ) ) {
((Book)stack.peek()).setTitle( tmp.toString() );

}else if( localName.equals( "author" ) ) {
((Book)stack.peek()).setAuthor( tmp.toString() );

}else if( localName.equals( "name" ) ) {
((Magazine)stack.peek()).setName( tmp.toString() );

}else if( localName.equals( "headline" ) ) {
((Article)stack.peek()).setHeadline( tmp.toString() );
}
// if none of the above, it is an unexpected element:
// necessary to push popped element back!
else{
stack.push( tmp );
}
}

// -----

/*
* is called when the parser encounters raw text.
*/
public void characters( char[] data, int start, int length ) {

// if stack is not ready, data is not content of recognized element
if( isStackReadyForText == true ) {
((StringBuffer)stack.peek()).append( data, start, length );
}else{
// read data which is not part of recognized element
}
}

// -----

private String resolveAttrib( String uri, String localName,
Attributes attribs, String defaultValue ) {

String tmp = attribs.getValue( uri, localName );
return (tmp!=null)?(tmp):(defaultValue);
}
}

[/code]


当遇到xml中元素开始标识"<", 会触发startElement, 遇到"/>"触发endElement.
[img]http://alanwu.iteye.com/topics/download/8f9575b1-9c08-46ca-af6e-5eed8f07d97b[/img]
图一分析了SAX解析XML,转换成Java Object的一个实例。

客户端使用将非常简单:

Driver.java

[code]
package benewu.gmail.study.tomcat.digester.unmarshalling;

import java.io.File;
import java.io.FileInputStream;
import java.net.URL;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

import benewu.gmail.study.tomcat.digester.Catalog;
import benewu.gmail.study.tomcat.digester.DigesterDriver;

public class Driver {

public static void main( String[] args ) {
Catalog catalog = null;

try {

URL fileURL = DigesterDriver.class.getResource("catalog.xml");
File file = new File(fileURL.getFile());
InputSource saxsrc = new InputSource( new FileInputStream( file ) );


System.out.println( "--- SAX ---" );
SaxCatalogUnmarshaller saxUms = new SaxCatalogUnmarshaller();

XMLReader rdr = XMLReaderFactory.
createXMLReader( "org.apache.xerces.parsers.SAXParser" );
rdr.setContentHandler( saxUms );
rdr.parse( saxsrc );

catalog = saxUms.getCatalog();
System.out.println( catalog.toString() );
}catch( Exception exc ) {
exc.printStackTrace();
System.out.println( "Usage: SAX|DOM filename" );
System.err.println( "Exception: " + exc );
}
}
}

[/code]

文章利用代码和图分析了SAX将XML转成Java Object。
这样可以使得客户端在XML中定义类的属性, 但是不能改变类。
Digester不但可以使客户在XML中定义类的属性, 可以改变不同类, 并且封装了SAX解析, 定义了各种Rule,利用策略模式进行组装类。

参考:

1 理解 SAX
http://www.ibm.com/developerworks/cn/views/xml/tutorials.jsp?cv_doc_id=84979

2 Java与XML联合编程之SAX篇
http://www0.ccidnet.com/tech/guide/2001/10/08/58_3392.html

[img]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值