什末是等级化数据集?我们为什末要关注它?
等级化数据集并不是一个新的概念。 在客户控制信息系统的事务化数据表单中,目录的文件中, 以及常用的JAVA对象中都存在着等级化数据集, 同样的,它也很明显的存在于XML中。在2001早期的XML 杂志中, 我发表了一个观点-程序员会受益于等级化数据抽,即使他们的很多数据源是显著相关的(比如数据库包括MySQL, Oracle, SQL Server, DB2, 等等。)。
在.NET世界中有一个相似的观点来自于“数据集”概念。虽然在我提议的等级化数据集和微软的数据集有很重要的不同,但是,很显然,等级化数据集通过丰富的细节化处理增强了相关的抽象提取。
这篇文章描述了Java API使用的分等级的数据集结构。不同于二年前XML 学报参考,您现在将会有可执行的代码片断,通过运行它,可以体验开始利用分等级的数据集。虽然程序员能使用Java编码来访问各种各样的数据源,以及构建最后的分等级的数据集,这篇文章可以通过简单地组成预构造的关系适配器,让您很容易的构建这些分等级的数据集。关系适配器包括文件阅读器、SQL阅读器、存储过程的阅读器,等等。
您大概会问:"这些分等级的数据集的好处在哪里?",虽然他们目前的作用还不是主导地位的,但是在编程界,等级结构数据集是相当有用的。对于初学者,一个完整的HTML页面所应具有的数据价值可以由一个等级结构数据集来满足。在一个MVC 模型中,一个servlet 控制器 能提供一个等级制度的数据集给JSP 页面,这个页面可以轻松的作它需要做的。 在数据准备方面,它能被转换成XML 并直接地通过servlet控制器返回到访问者。在应用方面,等级结构数据集能被转换成Excel 文档。在格式方面,等级结构数据集能重定向为一个报告引擎或一个支持XML 数据的绘制图表的引擎。
虽然文章的主要焦点是面向Java 程序员的Java 编程API,等级结构数据集能被非Non-Java 程序员相当有效地使用,直接地从关系数据库和其它数据源,同过使用像Tomcat这样的J2EE 服务器获得XML 、HTML ,或Excel 格式。闲言少讲,让我们研究一下等级结构数据集的结构,以及看看这些数据集是怎样被获得的(当放松一下您的编程肌肉) 。
等级化数据结构
一种等级化数据结构能概念性地描述为如同Java API ,或XML ,或某一其它格式。它最容易形象化地作为XML 。
<AspireDataSet
<!―一组在根级别的key value 对--
<key1val1</key1
<key2val2</key2
<!―一组指定的循环 --
<loop name="loop"
</loop
<loop name="loop2"
</loop
</AspireDataSet
这是一套key/value 对。给出的这套key/value 对能产生n 个独立的循环。各个循环本质上来说是一个数据表。这里,术语"循环" 与"表?±是同义的。 我没有使用"表" 是因为人们可能会根据字面意思来只采用表作为从关系表中取出的的唯一数据。被提及是行的集合(RowSet) ,让我们更加接近地看一下循环的结构:
<loop name="loopname"
<row
<!--一组key value 对--
<key1val1</key1
<key2val2</key2
<!--一组指定的循环--
<loop name="loopname1"
</loop
<!--一组指定的循环--
<loop name="loopname2"
</loop
</row
<row
</row
</loop
这里唯一的没有配对的是列的结构。列是期望的key/value对的集合。这里列不仅包括key/value 对,而且包括另外的一个n个独立循环的递归集。引伸一下可以生成任意数量深度的树。(或者我应该说,任意的高度!)
Java中的等级化数据结构
在我用XML显示等级化数据的时候,有一种可能性,就是人们也许采取一个等级化数据集逐字的访问XML数据,继而,逐字地使用DOM,继而,在JVM 里面消耗很多的内存。不过不必惊慌,等级化数据集有它自己的Java API,从而可以不使用DOM。多数的时候只是向前遍历加载数据树。下面是一个使用Java API 处理一个等级化数据集的例子:
package com.ai.htmlgen;
import com.ai.data.*;
/**
* 代表了一个等级化数据集。
* 一个hds 是一个行的集合。
* 你可以通过ILoopForwardIterator枚举这些行
* 你可以通过IMetaData 枚举各个列。
* 一个hds 也是一个基于当前行得循环集。
*/
public interface ihds extends ILoopForwardIterator
{
/**
*返回父级接口
* 如果没有父级接口则返回NULL
*/
public ihds getParent() throws DataException;
/**
* 基于当前行返回一系列的子循环名字。ILoopForwardIteraor 确当前行是什末。
*
*
* @see ILoopForwardIterator
*/
public IIterator getChildNames() throws DataException;
/**
* 通过给定的名字返回一个ihds 类型的Java子对象
*/
public ihds getChild(String childName) throws DataException;
/**
返回一个列,这跟对一个行集合进行求和,求平均很类似。
*/
public String getAggregatevalue(String keyname) throws DataException;
/**
返回这个循环或者表的列名字。
* @see IMetaData
*/
public IMetaData getMetaData() throws DataException;
/**
释放所有数据或表格循环使用的资源。
*/
public void close() throws DataException;
}
简而言之,Javaihds 接口描述了“面向等级数据集的接口。”这个API允许你使用循环递归调用。在运行时,有个选项指定只有当他们被要求的时候才加载这些循环。它也能够假定是仅仅向前还是随机遍历。在往下继续以前, 让我来介绍两个另外该API使用的接口:ILoopForwardIterator 和ImetaData。
如何在HDS中移动遍历一系列的行:ILoopForwardIterator
package com.ai.htmlgen;
import com.ai.data.*;
public interface ILoopForwardIterator
{
/**
* 根据匹配的钥匙从当前的行中获取相应的值
*/
public String getvalue(final String key);
public void moveToFirst() throws DataException;
public void moveToNext() throws DataException;
public boolean isAtTheEnd() throws DataException;
}
IMetaData: 用来读取列名
package com.ai.data;
public interface IMetaData
{
public IIterator getIterator();
public int
getColumnCount();
public int
getIndex(final String attributeName)
throws FieldNameNotFoundException;
}
你如何获取一个等级数据集, 从而你可以使用它?
现在我们知道了等级化数据集的结构, 你如何来控制它呢?根据我的经验, 这个在Aspire下会很容易。下面是所列的步骤:
1. 学习Aspire的基础。
2. 为你的等级化数据集创建一个定义文件。
3. 在Java代码中调用你得定义文件从而获取ihds。
下面对每一步进行详细的介绍。
阅读Aspire JAR的用法基础
Aspire 是一个小的JAR 文件,它可以直接运行, 特别的它可以被一个应用程序服务器调用,例如Tomcat。Aspire的核心是一套配置文件, 在这些文件中你可以通过Java类术语和这些类的参数声明数据访问机制。Aspire 将运行那些Java类并且返回结果对象。等级化数据集并非例外。
O'Reilly的一篇早期文章介绍了Aspire:"对于Tomcat的开发者来说, Aspire可以作为JAR"它会通过定义数据库和调用SQL以及存储过程来让你熟悉这些运作,就像配置和初始化Aspire一样。
为你的等级化数据集创建一个定义文件。
下面是一个等级化数据集的简单定义:
###################################
# ihdsTest 数据定义:1区
###################################
request.ihdsTest.className=com.ai.htmlgen.DBHashTableFormHandler1
request.ihdsTest.loopNames=works
#2区
request.ihdsTest.works.class_request.className=com.ai.htmlgen.GenericTableHandler6
request.ihdsTest.works.loopNames=childloop1
request.ihdsTest.works.query_request.className=com.ai.data.RowFileReader
request.ihdsTest.works.query_request.filename=aspire:\\samples
\\pop-table-tags\\properties\\pop-table.data
#3区
request.childloop1.class_request.classname=com.ai.htmlgen.GenericTableHandler6
request.childloop1.query_request.classname=com.ai.data.RowFileReader
request.childloop1.query_request.filename=aspire:\\samples\\pop-table-tags
\\properties\\pop-table.da