需求背景:
我们常常会看到数据库中的表是以id与其父id建立数据间的层级关系的,例如下图递归树数据结构:
通过上面的递归树数据,我们很难直观的得出表中数据共含有多少个层次。在进行报表制作的过程中,比如树形报表制作时,需要利用父id过滤选出的每层数据。在层数较多且层数不固定时报表制作将会相当麻烦。
本文利用递归算法,根据id与其父id一次性生成所有的层次,化递归树结构的数据为多层树形结构的数据供报表使用,可以大大简化报表制作的难度。
实现思路:
原数据集为递归数结构利用自定义数据集构建新的数据集,得到递归树的最大层级,根据最大层级构建数据集的列数,遍历原数据集的每一行数据,根据该行数据所在层数,填充其层数据和父层数据,最终得到多层级树形结构。其结构如下图所示:
具体实现:
1.自定义数据集类代码及说明:
publicclass MultiLevelDataSet implements IDataSetFactory{
public DataSet createDataSet(Context ctx, DataSetConfig dsc, boolean retrieve){
//读取同一报表中已算出的数据集,该数据集为递归数结构
DataSet ds1 = ctx.getDataSet("ds1");
//计算递归树最大层数
int maxlevel=getMaxLevel(ds1);
System.out.println("层数="+maxlevel);
//根据最大层数构造数据集ds2
DataSet ds2 = new DataSet("ds2");
for(int j=1;j<=maxlevel;j++){
ds2.addCol("level"+j);
}
for(int g=1;g<=ds1.getColCount();g++){
ds2.addCol(ds1.getColName(g));
}
//根据ds1的数据填充ds2中每行数据
for( int i = 0; i < ds1.getRowCount(); i++ ) {
Row row = ds2.addRow();
int level=getLevel(ds1.getData(i+1, 1).toString(),ds1);
String curid=ds1.getData(i+1, 1).toString();
while(level>0){
row.setData(level, curid);
curid=findParent(curid,ds1);
level--;
}
//拷贝ds1中原数据值ds2中对应列
for(int k=1;k<=ds1.getColCount();k++){
row.setData(k+maxlevel, ds1.getData(i+1, k));
}
}
System.out.println("ds2的总列数:"+ds2.getColCount());
return ds2;
}
//获取数据集中递归树的总层数
publicint getMaxLevel(DataSet ds){
int maxlevel=1;
//逐行遍历ds中的数据,计算每行数据所在层数,比较返回最大层数即为递归树最大层数
for( int i = 0; i < ds.getRowCount(); i++ ) {
int level=0;
level=getLevel(ds.getData(i+1, 1).toString(),ds);
if(level>maxlevel){
maxlevel=level;
}
}
return maxlevel;
}
//寻找当前节点(元素)的父元素
public String findParent(String id,DataSet ds){
for( int i = 0; i < ds.getRowCount(); i++ ) { if(id==ds.getData(i+1,1).toString()||id.equals(ds.getData(i+1,1).toString())){
return ds.getData(i+1,2).toString();
}
}
returnnull;
}
//计算元素的所在层数
publicint getLevel(String id,DataSet ds){
int level=0;
while(id!=null){
id=findParent(id,ds);
level++;
}
return level-1;
}
}
2.自定义数据集的配置:
3.转换为多层树形结构后的应用实例
(1)多层分组报表:
(2)树形结构报表:
(3)下拉树填报