| |
内容:
zeus 简介 预备知识 编译你的zeus 生成描述xml的java对象 marshal与unmarshal--xml与java object的转换 选择zeus的理由与思考 参考资料 关于作者
钟家豪 (judson78@yahoo.com.cn)
zeus可以将java对象与xml文件进行绑定,绑定使数据在j2ee中的应用更加方便。本文主要介绍zeus的编译与使用。对绑定过程中使用的dtd和xml文件也有说明。 1 zeus简介 enhydra是以生长于美国加利福尼亚海边的小水獭命名的非营利组织的名字。从但与著名的apache不同,enhydra致力于围绕application server的电子商务解决方案的研究。zeus就是enhydra开发的众多的工具软件中的一个,功能是对javaobject和xml进行数据绑定。它可以将任意的xml文件转化为对应的javaobject文件,并且将数据方便的在这两种形式之间转换。zeus最新版本是zeus1.0 beta 3.5,由于是完全的源码开放,可以到 http://zeus.enhydra.org/software/downloads/index.html 下载源代码后自己编译。
2 预备知识
2.1 用xml作为数据载体 xml(extensible markup language)由w3c组织制定并得到世界上几乎所有大公司的支持。xml是一种非常灵活的文本格式,与html相比,xml延续了其简单、易懂的语法,但是却有了更大的灵活性和扩展能力。例1是一段描述customer信息的xml文件,作为描述数据的语言,xml的组织形式很自由且表述清晰。
<?xml version="1.0" encoding="gbk"?> <customer customer_no= "00001"> < name>李俊</ name> <id_no>210106421016001</id_no> <sex >男</sex> <birth_place>大连</birth_place> <birth_date>1942-10-16</birth_date> <nationality>中国</nationality> <education>高中</education> <address>大连市沙河口</address> <contact_info id = "00001"> <zip_code>116001</zip_code> <tel_no>2645677</tel_no> </contact_info> </customer>
例1:描述customer的xml文件
这段xml结构很清晰:描述的是一个"顾客"实体,这个实体有其属性:姓名、身份证号、性别、出生地、生日、出生地、联系方式(邮编、电话)等。
第一行<?xml version="1.0" encoding="gbk"?>表述此xml文件的版本是1.0,用的是"gbk"的编码方式(如果要解析中文,gbk或gb2312是必须的)。<customer customer_no= "00001></customer>组成该文件完整的"根标记",customer_no是customer标记的"属性",<name></name>、<nationality></nationality>是<customer>的子标记。而在< contact></contact>中还可以继续包含子标记:<zip_code>、<tel_no>。用户自定义tag的xml语言给了用户足够的自由度表示数据,但是也为显示和解析带来了难度,为了解决这一问题,w3c在格式控制和标记定义上对xml加以限制。例如<customer></customer>就是一对不合格的标记。
2.2 dtd定义数据 dtd(document type definition)目的是定义xml文档中的元素和各元素间的关系。dtd可以与应用它的xml共存在一个文件中,也可以单独成为一个文件。例2是一个描述例1所述的xml文件的dtd文件。
<?xml version="1.0" encoding="gbk"?> <!element customer (name?,id_no?,sex?,birth_place?,birth_date?,nationality?, education?, contact_info?> <!attlist customer customer_no cdata #required > <!element name (#pcdata)> <!element id_no (#pcdata)> <!element sex (#pcdata)> <!element birth_place (#pcdata)> <!element birth_date (#pcdata)> <!element nationality (#pcdata)> <!element education (#pcdata)> <!element contact_info (zip_code?,tel_no?)> <!attlist contact_info id cdata #required > <!element zip_code (#pcdata)> <!element tel_no (#pcdata)>
例2:dtd文件
无规矩不成方圆,例2的dtd文件定义了例1的xml描述的customer元素,通过dtd的定义,xml中的标记都被赋予了意义,并且很好的解释了customer与其它元素之间的关系。dtd文件的存在使xml中的数据有了规定的形式,二者由如此紧密地联系容易联想到另外一种重要的数据组织方式--数据库的表中的字段和数据。dtd-xml这种与表结构-数据类似的结构为这两种技术的相互转换提供了天然的方便条件,借助于dtd,可以方便的将表中的数据用xml表示。
3 编译你的zeus 下载下来的zeus是一个zip文件,如果选择的是源代码下载,就必须首先编译才能够使用。本文介绍zeus的使用,首先从源代码的编译说起。
编译的方法在下载的docs文件夹中有详尽的描述,作为java技术阵营的一份子,zeus在将自己完全奉献的同时也使用了其他的一些杰出的java工具。比如编译就使用了apache的ant。可以在zeuslib下找到ant.jar文件。
在编译之前唯一要做的事就是设定好操作系统的java_home环境变量。例如在windows系统,如果jdk安装在d:/jdk1.3.1,则运行set java_home = d:/jdk1.3.1。完成了准备工作就可以开始编译zeus,ant本身是易于使用的编译工具,build.xml文件可以设定所有编译的细节和文件的组装。zeus的编译文件位于根目录下的build.xml,这个xml文件包含了对zeus编译并组装zeus.jar文件的一切细节而且有很高的可读性。
确定在zeus的根目录下,运行./bin/build.bat targets,ant可以找到位于当前目录下的build.xml文件,如果不输入任何参数,ant会输出提示要你输入编译targets:
compile:编译zeus的所有源代码,并将之放置于buildclasses下; bin:将原srcin下的文件拷到buildin下,原lib目录下的jar文件拷到buildlib下并将组合好的zeus.jar置于此文件夹下; doc:编译javadoc,并将结果拷到bindocsapidoc下。
sample和test分别用于编译例程和测试代码。如果不想一步一步编译,可以将targers参数设为all,这样ant就会以正确的次序为你自动编译好所有的targets。编译后的会出现一个build文件夹,所有编译好的文件都在这个文件中。检查build/bin文件夹,出现的zeus.jar文件就是编译好的工具。如果你有足够的经验去修改zeus的源代码和build.xml文件,完全可以打造属于你自己的zeus。
4 生成描述xml的java对象 生成java对象的第一步是使用zeus自动生成java源代码。使用zeus的批处理文件在buildin的zeus.bat,使用语法如下:
zeus.bat -constraints= [-outputdir=] [-collapsesimpleelements=] [-ignoreidattributes=] [-javapackage=] [-root=]
参数解释如下:
参数 必须 默认值 描 述 constraints yes 无 指定产生java代码的约束文件(dtd或xsd.文件) outputdir no 当前目录 放置生成java文件的根目录 collapsesimpleelements no false 是否支持简单元素的精简,所谓"简单元素"就是在dtd文件中描述的没有属性(attribute)的元素(element)。如果这样的简单元素以"精简"形式被zeus解析,则生成的java类使用其父元素的get[elementname]()的形式来得到xml中该元素的值,这种形式比普通的get[elementname]().getcontent()的形式更简便。而且减少了很多不必要的生成类。 ignoreidattributes no false 此参数设定判断"简单元素"的条件:是否将id属性作为条件。设定此参数为true会导致那些只有一个"id"属性的元素被看作是"简单元素" javapackage no 无 指定生成的java类的包。例如:指定com.zjh.tools后,所有生成的java类都在com.zjh.tools包内。 root no 由dtd解析器决定 确定用于解析的根元素。解析有多个顶级元素的dtd文件时,指定根元素使之生成正确的java类。
继续上面的例子,将例1的xml文件与java objects绑定,第一步要生成java文件,具体方案就是使用zeus.jar中的org.enhydra.zeus.util.dtdsourcegenerator,例2中的customer.dtd文件作为必须的constrains参数。首先执行下列命令:
将customer文件置于c:zeusdtd文件下,建立c:zeuszjhsample,执行下列命令: c:zeus>.uildinzeus.bat -constraints=dtdcustomer.dtd -outputdir=zjhsample -javapackage =com.zjh.zeustest.binding -collapsesimpleelements=true
查看c:zeuszjhsamplecomzjhzeustestinding文件夹,发现生成了六个文件:customer.java、customerimpl.java、contact_info.java、contact_infoimpl.java、customerunmarshaller.java、unmarshallable.java。
生成的类名有规可循:customer、contact_info是dtd文件中非简单元素的名称,zeus生成与其同名的接口;customerimpl、contact_infoimpl是实现这两个接口的类。customerunmarshaller与unmarshallable看起来有些奇怪,但也不是凭空而来:unmarshallable接口继承自org.xml.sax.contenthandler,提供解析xml合法性的接口,所有的elementimpl类都要继承该接口;customerunmarshaller提供反解码xml的接口,将xml文件输入,返回customer对象。
数据绑定的所有秘密都隐藏在这几个文件中,可以用任何的文本编辑器对其进行编辑。但是就像程序声明所述:修改这些程序也许会导致数据绑定操作的失败。
最后编译这六个java文件:javac *.java,生成class文件。这样,就得到了用于描述xml文件的java类。
5 marshal与unmarshal--xml与java object的转换 通用的xml文件适合不同技术平台之间的数据传输,java对象可以为java程序提供更加方便的使用接口,通过zeus工具生成的java object就像是一座桥梁,将二者紧密地联系在一起(见图1)。它不仅在内部构建了足够的用来描述xml文件各个元素值的属性,更提供了可以将java对象与xml文件相互转化的接口:unmarshal和marshal。
unmarshal:将xml文件"反解码"为javaobject;
marshal:将javaobject"解码"为xml文件。
图1:java对象与xml文件的转换
5.1 unmarshal xml文件到java对象 一旦用zeus生成的java对象被编译,将xml文件转化为java形式的表述就变成了一件简单且惬意的事。这一过程被描述为"反解码(unmarshal)",其实它是zeus根据dtd文件生成的elementimp对象的unmarshal()方法。如同科幻小说中的物品自动制造机,向unmarshal方法投入以java file、writer、或inputstream形式包装的xml文件,一按unmarshal按钮,xml数据的java表示版就轻而易举的诞生了。示例程序(例3)中的customerunmarshal类完成了unmarshal例1中customerinfo.xml的工作,并把结果输出到屏幕上。
package com.zjh.zeustest; import java.io.*; import com.zjh.zeustest.binding.*;
public class customerinfo { public static void main(string[] args) { if(args.length!=1){ system.out.println("please in put the location of xml file"); return; } try{ customer customer = customerunmarshaller.unmarshal((new file(args[0])),false); system.out.println("姓名:"+customer.getname()); system.out.println("证件号码:"+customer.getid_no()); system.out.println("性别:"+customer.getsex()); system.out.println("出生地:"+customer.getbirth_place()); system.out.println("国籍:"+customer.getnationality()); system.out.println("学历:"+customer.geteducation()); system.out.println("邮政编码:"+customer.getcontact_info().getzip_code()); system.out.println("电话号码:"+customer.getcontact_info().gettel_no()); }catch(exception e){ e.printstacktrace(); } } }
例3 unmarshal xml
编译该程序后用下列命令运行: java -classpath .;..libxerces.jar com.zjh.zeustest.customer unmarshal ..cust.xml
输入如下:
姓名:李俊 证件号码:210106421016001 性别:男 出生地:大连
国籍:中 国 学历:高 中 邮政编码:116001 电话号码:2645677
5.2 marshal java对象到xml文件 把数据从java object的形式转换为xml文件是unmarshal的逆过程,在语义上用的也是marshal(解码)这一名词。下面提供的例子(例4)提供一个数据绑定使用完整的例子:
将cust.xml读入 unmarshal xml 修改java对象的属性值 marshal java对象
package com.zjh.zeustest; import java.io.*; import com.zjh.zeustest.binding.*;
public class customermarshal {
public static void main(string[] args) { if(args.length!=1){ system.out.println("please in put the location of xml file"); return; } try{ customer customer = customerunmarshaller.unmarshal((new file(args[0])),false); contact_info contactinfo = customer.getcontact_info(); contactinfo.setid("0002"); contactinfo.setzip_code("116001"); contactinfo.settel_no("6656456"); customer.setbirth_date("1979-10-1"); customer.setbirth_place("大连"); customer.setcontact_info(contactinfo); customer.setcustomer_no("1234566"); customer.seteducation("大学"); customer.setid_no("210204197910012233"); customer.setname("李明"); customer.setnationality("中国"); customer.setsex("男"); customer.marshal((new file("marshalcust.xml"))); }catch(exception e){ e.printstacktrace(); } } }
例4 marshal javaobject
执行该程序后生成的新的marshalcust.xml如下所示:
<?xml version="1.0" encoding="utf-8"?>
<!doctype customer system "d:zeusdtdcustomer.dtd"> <customer customer_no="1234566"> <name>李明</name> <id_no>210204197910012233</id_no> <sex>男</sex> <birth_place>大连</birth_place> <birth_date>1979-10-1</birth_date> <nationality>中国</nationality> <education>大学</education> <contact_info id="0002"> <zip_code>116001</zip_code> <tel_no>6656456</tel_no> </contact_info> </customer>
选择zeus的理由与思考: java与xml是一对天生的兄弟,在所有计算机软件技术都高举xml大旗的时候,有一万个理由实现java与xml的完美结合。sun、apache也提供了功能强大xml解析包,站在巨人的肩膀上(实际上zeus使用了apache的xerces来解析xml),zeus提出的是数据绑定的概念。
从解析到绑定不需要很复杂的实现手法,但却提供给使用者更加简单和灵活的解决方案。编程技术的发展和开放软件的出现为创意提供了更广阔的空间,选择zeus,使用zeus,思考zeus--没有复杂的技术,只有令人赞叹的创意。这也许就是后软件时代程序生存的真谛,我想。
关于作者 钟家豪,目前在中国广东从事金融领域的软件开发,主要致力于j2ee架构、xml、webservice和数据库方面的研究。可以通过 judson78@yahoo.com.cn 与他联系。
|
|