| 教您如何用zeus实现xml-java的数据绑定 |
| 作者:钟家豪 | 来源:http://www.cjsdn.net |
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文件的版本是1.0,用的是"gbk"的编码方式(如果要解析中文,gbk或gb2312是必须的)。、是的子标记。而在< contact>中还可以继续包含子标记:、。用户自定义tag的xml语言给了用户足够的自由度表示数据,但是也为显示和解析带来了难度,为了解决这一问题,w3c在格式控制和标记定义上对xml加以限制。例如就是一对不合格的标记。 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。可以在zeus/lib下找到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的所有源代码,并将之放置于build/classes下; bin:将原src/bin下的文件拷到build/bin下,原lib目录下的jar文件拷到build/lib下并将组合好的zeus.jar置于此文件夹下; doc:编译javadoc,并将结果拷到bin/docs/apidoc/下。 sample和test分别用于编译例程和测试代码。如果不想一步一步编译,可以将targers参数设为all,这样ant就会以正确的次序为你自动编译好所有的targets。编译后的会出现一个build文件夹,所有编译好的文件都在这个文件中。 检查build/bin文件夹,出现的zeus.jar文件就是编译好的工具。如果你有足够的经验去修改zeus的源代码和build.xml文件,完全可以打造属于你自己的zeus。 4、生成描述xml的java对象 生成java对象的第一步是使用zeus自动生成java源代码。使用zeus的批处理文件在build/bin/的zeus.bat,使用语法如下: zeus.bat -constraints= [-outputdir=] [-collapsesimpleelements=] [-ignoreidattributes=] [-javapackage=] [-root=] 将例1的xml文件与java objects绑定,第一步要生成java文件,具体方案就是使用zeus.jar中的org.enhydra.zeus.util.dtdsourcegenerator,例2中的customer.dtd文件作为必须的constrains参数。首先执行下列命令: 将customer文件置于c:/zeus/dtd文件下,建立c:/zeus/zjhsample,执行下列命令: c:/zeus>./build/bin/zeus.bat -constraints=dtd/customer.dtd -outputdir=zjhsample -javapackage =com.zjh.zeustest.binding -collapsesimpleelements=true 查看 c:/zeus/zjhsample/com/zjh/ zeustest/binding文件夹, 发现生成了六个文件: 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 ./;../lib/xerces.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:/zeus/dtd/customer.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--没有复杂的技术,只有令人赞叹的创意。这也许就是后软件时代程序生存的真谛,我想。 |

闽公网安备 35060202000074号