浏览 4160 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2007-11-23
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使用。 数据绑定概念: 编组(Marshalling)是把内存中的数据转化到存储媒介上的过程。因此在 Java 和 XML 环境中,编组就是把一些 Java 对象转化成一个(或多个) XML 文档。在数据库环境中,则是把 Java 表示的数据存入数据库。显然,编组的秘密在于把 Java 实例中的面向对象结构转化成适用于 XML 的 扁平结构,或者 RDBMS 中的关系结构(使用 Java 技术转换到 OODBMS 实际上很简单)。 解组(Unmarshalling)是把数据从存储媒介转换到内存中的过程--正好与编组相反。因此需要把 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文件 <?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> Catalog.java 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(); } } Book.java 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 + "'"; } } Magazine.java 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(); } } Article.java 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 + "' "; } } 定义好了类和对应的xml配置, 开始利用catalog.xml进行初始化Catalog吧。 SaxCatalogUnmarshaller继承DefaultHandler, 重写关键的两个分方法:startElement和endElement SaxCatalogUnmarshaller,java 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); } } 当遇到xml中元素开始标识"<", 会触发startElement, 遇到"/>"触发endElement. 图一分析了SAX解析XML,转换成Java Object的一个实例。 客户端使用将非常简单: Driver.java 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 ); } } } 文章利用代码和图分析了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] 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2007-12-02
以上类中怎么少一个“DigesterDriver.class”类?请楼主贴出来
|
|
返回顶楼 | |
发表时间:2007-12-02
不好意思, DigesterDriver在第二篇文章里面。http://alanwu.iteye.com/admin/show/143911
在这里只是复用了DigesterDriver来寻找catalog.xml路径的方法 |
|
返回顶楼 | |