薛谷雨([email protected])
NORDSAN信息科技开发有限公司高级JAVA工程师
2003年12月
前言
数据交换是一个传统的课题,随着近两年XML标准的出现和日益成熟,并很快成为各种复杂的异构数据的交换得以实现的核心技术。JAVA作为一门针对网络的纯面向对象的编程语言,与XML结合得天衣无缝。由于两者都具有平台无关性,是数据交换领域里服务器端实现技术的首选。在java中对xml数据进行硬编码操作是目前开发人员普遍采用的方式,但代码的复用性和维护性很差,在数据交换格式的设计变更后,代码将有翻天覆地的变更,造成了整个软件产品的内在不稳定性,及开发进度的停滞甚至倒退。由于xml是一新兴技术,全球各个企业中也刚刚开始建立起数据交换的概念,数据交换格式各有各的标准,跨行业,跨企业的数据交换由于数据格式的互不兼容的原因,是一个十分棘手的问题。开发人员往往在将xml数据格式化成企业自有系统所能识别的xml格式这个问题上频繁更改以前代码或衍生出各种版本,陷入数据格式的泥沼之中。下面将要介绍的技术将解决这一问题,将数据采集与数据转换分成两个互相独立的模块,充分利用XSLT这一新兴技术给我们带来的便捷,将数据转换这一环节从JAVA代码中分离,带给开发人员一个全新的开发思路,最大限度的提升软件产品或项目中关系型数据向XML型数据转换这一核心流程的开发效率。
传统的DB-XML数据交换方式
关于XSLT
XSLT用于将一个XML文档转换成另一个XML文档或另一种类型的文档,也就是将一个XML文档转换成浏览器所能识别的一种格式。这其中之一就是HTML。通常,XSLT将每个XML元素都转换成一个HTML元素。 XSLT还可以向输出文件中增加全新的元素,或去掉一些元素。它可以重新安排这些元素并对元素进行分类,测试并确定显示哪些元素等等。 描述这种转换过程的一个常用说法是:XSL用XSLT将一个XML来源树转换成另一个XML结果树(或将一个XML源文档转换成另一个XML结果文档)。
鲜为人知的秘籍-xalan便捷的数据库查询功能
xalan-java是一套xslt处理器,用来将XML文件转换为HTML,TEXT和XML等其他类型文件格式。支持XSLT1.0和XPATH 1.0版。开发人员可以通过命令行方式或在JAVA APPLET和SERVLET中使用,并可以作为自己开发的应用程序的类库使用。xalan-java实现的是transformation API for XML(TRaX)接口,此接口为jaxp1.2标准中的一部分。TraX提供一个模块化的架构和标准的api以执行xml的转换,并且会根据配置设定决定使用哪一个转换器和xml语法分析器。
Xalan-java制订的关于SQL的XSLT扩展库详解
XSLT扩展库的概念
当最基本的XSLT语法不能满足的开发工作时,你一定设想开发一套自己的XSLT扩展语法,幸运的是Xalan-Java让你的这种想法变成现实。XSLT的扩展元素和函数为像xalan这样的XSLT处理器提供了强大的扩展功能。Apache组织也提供一些扩展库支持,在JAVA开源爱好者共同努力下,我们将获得更多的可以工作在xalan/java上的扩展,简化我们的开发工作。这里我们主要介绍的是xalan-java自带的SQL扩展库。
SQL扩展库
SQL扩展的xml命名空间是http://xml.apache.org/xalan/sql, 它能实现的功能有通过JDBC驱动建立数据库连接,执行一个SQL查询并取得结果集。用于数据库查询的SQL语句可以在xsl文件中直接给出或者通过java程序传入xsl文件。本文中的实例采用后一种方式,此方式更具有实用性。SQL扩展库中也有类似于JDBC的结果集的概念。"流化"(streamable)的结果集是此扩展库取得结果集的默认方式。如果你采用此模式,你一次只能从结果集中取出一条记录,特别注意的是,在你的样式表单中对结果集document使用XPATH表达式将可能导致不可预期的结果。XALAN库中关于SQL的扩展的核心java类是org.apache.xalan.lib.sql.Xconnection,它提供了SQL扩展的所有功能。Java的函数的名称就是xsl文件中sql扩展功能函数的名称。下面介绍这个类的几个主要方法:
new():通过连接池建立一个数据库连接。SQL扩展库提供一个默认的连接池的实现,你也可以通过JAVA类的方式实现自己的连接池,这是一个比较复杂的技术在此不作讨论。 query():通过数据库连接执行一个查询,类似JDBC中的connection.executeQuery() enableStreamingMode():打开记录集的流模式,一次只返回一条记录。 disableStreamingMode():关闭记录集的流模式,返回结果集中的全部记录。 close():关闭数据库连接,类似于JDBC的close()方法。query()函数返回一个document,包含了jdbc中ResultSetMetaData中对结果集的描述信息和当前记录中各个字段的值。
上面是从java实现的层面简单介绍了一下xalan的sql扩展库的功能,下面就其在XLST中的具体使用方法,进行详细的讲解。
通过JAVA程序创建数据库连接池:
下面代码将演示通过java程序建立一个SQL扩展库的连接池:
//初始化一个连接池管理器 ConnectionPoolManager cpMng=new ConnectionPoolManager(); //构造一个默认的连接池 DefaultConnectionPool cp = new DefaultConnectionPool(); //将数据库的jdbc驱动程序填入连接池,此处用mysql的jdbc驱动 cp.setDriver("org.gjt.mm.mysql.Driver"); //将数据库的url填入连接池 cp.setURL("jdbc:mysql://localhost/sppix"); //将数据库的连接用户名填入连接池,此例的用户名是root cp.setUser("root"); //将数据库的连接密码填入连接池,此例的用户密码为空。 cp.setPassword(""); //设置连接池 cp.setMinConnections(10); //设置连接池的开启状态 cp.setPoolEnabled(true); //注册连接池到连接池管理器 cpMng.registerPool("sppixpool",cp);
在XSLT中使用连接池建立数据库连接
Error Connecting to the Database
我们用db这个变量存储一个数据库连接,sql:new()声明此变量是个数据库连接;sql:connect($db, 'sppixpool')是从名称为sppixpool的数据库连接池中创建一个数据库连接,这个连接池由上一步的java程序片断实现; sql:getError($db)/ext-error用来打印连接数据库的错误信息,错误信息的内容对应于java.sql.SQLException中的内容; sql:disableStreamingMode($db)用来设置此连接为非流模式,以便返回结果集中的全部记录,否则只能返回一条数据记录。
在XSLT中进行数据库查询
第一条语句声明一个变量名称为query,这个变量的值是一条SQL语句"select * from cat",第二条语句执行查询并将查询的结果赋给变量table。
Table是一个结果集变量,对应xalan扩展库中的org.apache.xalan.lib.sql.SQLDocument,在xslt中,可以通过 xpath的描述方式取出其内部的各级对象。那所谓各级对象,具体包含哪些对象呢?xalan的文档中并没有明确的文字进行说明,但有下面几个是常用的。Sql是根结点元素,下面的二级节点元素是row-set,这个节点类似于JDBC中的ResultSet这个对象;自然row-set这个节点元素的下一级是row这个节点元素,它对应于一条数据库记录。你可以通过xpath的方式访问到这条记录,语法是
(注:其中的$table这个变量在上一节中曾经定义过,对应数据库中的表)
row下面是col,对应每个数据库表中的一条记录的一个字段。另外col有一个方法text(),就是取出col中的值的文本表示形式。column-label是col的一个属性,记录了字段的名称。可以通过xpath中@column-label的语法将其取出。
在XSLT中断开数据库连接
其中的$db是上面曾定义过的数据库连接,这行语句的功能就是在数据库连接使用完后,断开数据库的连接。
驾驭xalan,轻松实现关系型数据库到XML的数据交换
前面详细介绍了xalan从关系型数据库获取数据的方法,下面将给出一个完整且有应用价值的例子,通过它,你将真正掌握这种简单快捷的数据交换方式。
这个例子要做的事情很简单,就是从一个名称为sppix的关系型数据库中的名称为cat的表中,根据条件查询出一组数据,并按照特定的xml格式输出到文件中(当然在真正应用中,这个xml数据只是个中间体,有了它,你可以随心所欲的进行任何xml操作)。为了读者便于调试,本例中的关系型数据库采用流行且免费的mysql数据库,jdk的版本是1.3.1,java程序要用到的全部类库在本文最后的“有用的资源和参考资料”中给出。整个过程由一个java程序调用xsl模版文件完成,java程序的流程是读入xsl文件,将标准sql格式的查询语句倒入到内存的xsl对象中,通过xalan输出到xml文件。Java程序负责数据采集,xsl模版文件负责数据的转换和呈现。这个实例代码的一个特别之处就在于xsl文件只需撰写一次,无需更改,便适应任何的查询要求,生成统一的xml格式,因为对数据的采集都已经隐藏在java文件中了;另一方面,在工程项目中,程序无需关心生成的xml格式,在用户或合作开发者要求改变xml的交换格式时,无需更改java代码,只需简单的更改一下xsl文件,便可以满足要求,极大的提高的java代码的可复用型,这在实际的工作中将提高整个开发组的工作效率。Java的强大加上xalan的简捷清晰,给数据交换方式注入了新的生命力。
在阅读如下章节之前,你应该具有java通过jdbc访问mysql数据库的基本技能,并掌握xml的概念及如何通过java操纵xml,并掌握xpath的概念和知识。另外至少应该知道xalan是做什么用的,如果对xalan还感到陌生建议先阅读有关xalan的入门资料。在此并不会对以上技术的基本入门知识进行介绍。
搭建数据库环境
本例中在MYSQL数据库中创建一个名称为sppix的数据库,在数据库中建立表并插入样例数据的sql语句如下:
# # Table structure for table 'cat' # CREATE TABLE cat ( cat_id varchar(32) NOT NULL default '0', name varchar(16) NOT NULL default '', sex char(1) default NULL, weight float default NULL, PRIMARY KEY (cat_id) ) TYPE=MyISAM; # # Dumping data for table 'cat' # INSERT INTO cat VALUES("0001", "小白", "F", "7.4"); INSERT INTO cat VALUES("0002", "小黑", "M", "7.4");
这个表记录了猫咪的基本信息,每个字段的含义依次是猫咪的编号,爱称,性别(F代表雌性,M代表雄性)及体重。
撰写xsl文件
xsl文件的文件名为sample1.xsl
Error Connecting to the Database Error in Query
java代码的设计思想
一个简单而完整的java实现代码:
package xmljdbc; import java.io.*; import org.apache.xalan.lib.sql.ConnectionPoolManager; import org.apache.xalan.lib.sql.DefaultConnectionPool; import org.apache.xpath.XPathAPI; import javax.xml.transform.TransformerFactory; import javax.xml.transform.Transformer; import javax.xml.transform.stream.StreamSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.dom.DOMSource; import org.apache.xml.serializer.WriterToUTF8; public class Sample1 { public Sample1() { } public static void main(String[] args) throws Exception{ //初始化一个连接池管理器 ConnectionPoolManager cpMng=new ConnectionPoolManager(); //构造一个默认的连接池 DefaultConnectionPool cp = new DefaultConnectionPool(); //将数据库的jdbc驱动程序填入连接池,此处用mysql的jdbc驱动 cp.setDriver("org.gjt.mm.mysql.Driver"); //将数据库的url填入连接池 cp.setURL("jdbc:mysql://localhost/sppix"); //将数据库的连接用户名填入连接池 cp.setUser("root"); //将数据库的连接密码填入连接池 cp.setPassword(""); //设置连接池 cp.setMinConnections(10); //设置连接池的开启状态 cp.setPoolEnabled(true); //注册连接池到连接池管理器 cpMng.registerPool("sppixpool",cp); //用xml工具解析XSL文件 javax.xml.parsers.DocumentBuilderFactory dbf=javax.xml.parsers.DocumentBuilderFactory.newInstance(); javax.xml.parsers.DocumentBuilder db=dbf.newDocumentBuilder(); org.w3c.dom.Document doc=db.parse("/sample1.xsl"); //通过XPATH将XSL文件中的路径为/stylesheet/param[@name="query"]的节点的值替换为sql查询语句 org.w3c.dom.Node node=XPathAPI.selectSingleNode(doc.getDocumentElement(),"/stylesheet/param[@name=\\"query\\"]"); ((org.w3c.dom.Element)node).setAttribute("select","'select * from cat'"); //创建一个transformer TransformerFactory tFactory = TransformerFactory.newInstance(); DOMSource doms = new DOMSource (doc); Transformer transformer = tFactory.newTransformer(); StringReader reader = new StringReader(" "); StringWriter writer=new StringWriter(); //输出修改后的xsl数据流到StringWriter transformer.transform(doms,new StreamResult(writer)); //根据xsl数据流生成整合了数据库查询结果的xml文档 Transformer transformer1 = tFactory.newTransformer( new StreamSource(new StringReader(writer.toString()))); //输出到名称为"result.xml"的xml文件中 transformer1.transform(new StreamSource(reader), new StreamResult(new FileOutputStream("result.xml"))); } }
运行结果
生成一个名称为result.xml的文件:
0001 小白 F 7.4 0002 小黑 M 7.4
后记
读过此文,你一定会对XSLT和xalan有一个新的认识,一定会说“啊,xalan居然还可以这样用”。是的,如果仅仅将xslt当作一种html时代css样式表的替代品,控制一下网页的输出或作为一种数据呈现的终端工具,这种想法就过于狭隘了。我们应该站在更高一些的角度,俯视一门新兴技术真正能给我们的开发方式和开发思想带来怎样的革命。在以后的文章中我将对xalan的其他高端技术进行一一介绍,技术永无止境!
一些有用的资源和参考资料
本文附件提供了此文中的全部源代码,可编译运行,供读者研究。
xalan工具库的最新版本可以在apache的官方网站下载:http://xml.apache.org/xalan-j/index.html
欲了解有关XSLT的更多内容和最新消息,请参阅 http://www.w3.org/Style/XSL/
W3C组织关于XSLT扩展的建议 http://www.w3.org/TR/xslt - extension
本文中用到的mysql数据库可以在 http://www.mysql.com/ 中免费获得。
Mysql数据库的jdbc驱动程序可以在下面网址下载:http://mysql.ihostunit.com/Downloads/Contrib/mm.mysql-2.0.4-bin.jar
对xpath感兴趣的读者可以参考xpath的最新规范:http://www.w3.org/TR/xpath , 另外提供一个不错的网站 http://www.zvon.org/xxl/XPathTutorial/General/examples.html ,提供xpath的教程和在线联系,让你轻松掌握xpath这一技术。
关于作者薛谷雨是NORDSAN(北京)信息科技开发有限公司高级JAVA研发工程师,正致力于企业级异构数据交换的服务器产品的研发,在J2EE和WEB SERVICE方面有较为丰富的开发经验,你可以通过 [email protected] 与他取得联系。
本文地址:http://com.8s8s.com/it/it16213.htm