精华内容
下载资源
问答
  • 报表在数据准备阶段往往要根据实际业务进行各种判断计算以后才能得到最终的...计算逻辑并不算复杂,但使用SQL却很难做,用存储过程(要取首尾记录)也很麻烦,而一般的报表工具由于不具备强计算能力,常常只能写用

           报表在数据源准备阶段往往要根据实际业务进行各种判断计算以后才能得到最终的报表数据源,而使用SQL在这种情况下则难于编写,http://bbs.csdn.net/topics/390938280中提到的考勤问题就是其中之一,这个计算看起来是给财务或人力部门的考勤报表服务的。计算逻辑并不算复杂,但使用SQL却很难做,用存储过程(要取首尾记录)也很麻烦,而一般的报表工具由于不具备强计算能力,常常只能写用Java等写自定义数据源实现。

           使用润乾集算报表来做则比较简单,这里以上述链接中的实际业务为例,给出集算报表的实现方案。

    报表背景

           源数据如下:


           现需要在报表中以日期和性能统计考勤情况,要求根据:每天7点到12点算上班打卡,16点以后算下班打卡,多次刷卡取最早的打卡时间为上班卡,取最晚时间为下班卡,如果在该时间段未存在打卡记录即显示未打卡,8点30之后打卡算迟到,18点之前下班算早退。得到类似下表结果:

             这个报表的难点在于用SQL或存储过程写起来很困难,而一般报表工具则不具备数据源计算能力,根本无法实现。

    集算报表本身内置了适合结构化计算的脚本,可以方便地写出数据准备的计算(相当于一种更使用更简单的自定义数据集)。上述报表需求使用集算报表可以这样完成:

    编写集算脚本

           首先使用集算脚本编辑器,新建集算脚本,设置脚本参数,如刷卡起止时间范围:

           编写脚本完成数据计算,为报表输出计算后结果集。

     

    A

    B

     

    1

    =connect("kaoqin")

     

     

    2

    =A1.query("select * from 考勤表 where 刷卡时间>=? and 刷卡时间<=?",b_date,e_date order by 员工工号,刷卡时间)

    3

    =A2.group(员工姓名,date(刷卡时间))

    4

    =create(日期,员工姓名,上班,下班,是否迟到,是否早退)

    5

    for A3

    =A5(1).刷卡时间

    =string(time(B5))

    6

     

    =A5.m(-1).刷卡时间

    =string(time(B6))

    7

     

    =if(C5>="07:00:00" && C5<="12:00:00",B5,"未打卡")

    8

     

    =if(C6>="16:00:00",B6,"未打卡")

    9

     

    =if(C5>="08:30:00" && C5<="12:00:00","迟到",if(C5<="08:30:00","","未打卡"))

    10

     

    =if(C6>="16:00:00"&& C6<="18:00:00","早退",if(C6>="18:00:00","","未打卡"))

    11

     

    >A4.insert(0,date(A5.刷卡时间),A5.员工姓名,B7,B8,B9,B10)

    12

    result A4

     

     

           A1:连接数据源;

           A2:根据指定时间范围,执行sql查询考勤表数据,查询结果按照员工和刷卡时间排序,排序是为了便于后续取得首尾记录;

           A3:按照员工和刷卡日期分组,与SQL不同,集算脚本中的分组结果保留了分组成员;

           A4:创建空结果序表;

           A5-C11:循环A3中的分组,根据最早和最晚刷卡时间通过判断计算员工的出勤情况,最后将结果写回到A4结果序表中;

    其中,B6通过A5.m(-1)取得了最后一条记录,集算报表中的集合都是有序的,所以很容易通过序号取得相应成员,这与SQL的集合无序有很大区别;

           A12:为报表返回结果集。

    编辑报表模板

           使用集算报表编辑器,编辑报表模板,用于数据展现。首先新建参数,并设置默认值。

           新建报表并设置集算器数据集,调用上述编辑好的脚本文件。

           其中,dfx文件路径既可以是绝对路径,也可以是相对路径,相对路径是相对选项中配置的dfx主目录的;参数b_date和e_date为脚本参数,begin和end为报表模板参数,事实上二者可以同名。

            

           编辑报表表达式,直接使用集算脚本返回的结果集,完成报表制作。

           报表展现结果如下:

           可以看到,使用集算器脚本可以快速完成这类带有多重判断的情况。而且外置的集算脚本具有可视化的编辑调试环境,编辑好的脚本还可以复用(被其他报表或程序调用)。不过,如果脚本已经调试好,而且不需要复用的时候,要维护两个文件(集算脚本和报表模板)的一致性会比较麻烦,这时候直接使用集算报表的脚本数据集就比较简单了。

           在脚本数据集中可以分步编写脚本完成计算任务,语法与集算器一致,还可以直接使用报表定义好的数据源和参数。本例使用脚本数据集可以这样完成:

           1.  在数据集设置窗口中点击“增加”按钮,弹出数据集类型对话框,选择“脚本数据集”;

           2.  在弹出的脚本数据集编辑窗口中编写脚本;

           这里可以看到,在脚本数据集中直接使用了报表中定义好的数据源kaoqin和参数begin和end,比起单独的集算脚本更加简单、直接。

           3. 报表模板和表达式与使用集算器数据集方式一致,不再赘述。


    展开全文
  • 报表数据之Hadoop

    千次阅读 2015-04-28 10:09:43
    集算报表支持的数据类型除传统的关系型数据库外,还支持:TXT文本、Excel、JSON、HTTP、Hadoop、mongodb等。  对于Hadoop,集算报表既可以直接访问Hive,也可以读取HDFS中的数据,完成数据计算和报表开发。Hive的...

            集算报表支持的数据源类型除传统的关系型数据库外,还支持:TXT文本、Excel、JSON、HTTP、Hadoop、mongodb等。

             对于Hadoop,集算报表既可以直接访问Hive,也可以读取HDFS中的数据,完成数据计算和报表开发。Hive的访问和普通数据库一样使用JDBC就可以,这里不再赘述了。下面通过一个例子来看直接访问HDFS的过程。

    报表说明

           股票交易记录按月以文本形式存储在HDFS中,文件名为stock_record_yyyyMM.txt(如stock_record_200901.txt),内容包括股票代码、交易日期和收盘价。根据指定月份查询并计算各只股票的收盘均价,以便进行股价趋势分析。文本内容如下:

           code                   tradingDate     price

           120089     2009-01-0100:00:00        50.24

           120123     2009-01-0100:00:00        10.35

           120136     2009-01-0100:00:00        43.37

           120141     2009-01-0100:00:00        41.86

           120170     2009-01-0100:00:00        194.63

           区别于一般报表工具,集算报表可以直接访问HDFS完成数据的读取计算,以下为实现过程。

    拷贝相关jar包

           使用集算报表访问HDFS时需要加载Hadoop核心包及配置包,如:commons-configuration-1.6.jar、commons-lang-2.4.jar、hadoop-core-1.0.4.jar(Hadoop1.0.4)。将以上jar拷贝到[集算报表安装目录]\report\lib和[集算器安装目录]\esproc(如果需要使用集算器编辑器编辑和调试脚本的话)下。

    编写计算脚本

           使用集算编辑器编写脚本(stockFromHdfsTxt.dfx),完成HDFS的文件读入和数据过滤,为报表返回结果集。由于要接收报表传递的参数,首先设置脚本脚本参数。


           编辑脚本。

           A1:使用hdfsfile函数根据文件路径和指定参数创建HDFS文件游标;

           A2:针对股票代码汇总收盘价和数量;

           A3:计算每只股票的平均收盘价,通过A4为报表返回结果集。

    编辑报表模板

           使用集算报表设计器新建报表模板,并设置参数:

           设置数据集,使用“集算器”数据集类型,调用编辑好的脚本文件(stockFromHdfsTxt.dfx)。

           其中,dfx文件路径既可以是绝对路径,也可以是相对路径,相对路径是相对选项中配置的dfx主目录的。

     

           编辑报表表达式,直接使用集算脚本返回的结果集,完成报表制作。

           值得注意的是,在报表设计器中预览时,需要将Hadoop相关jar包拷贝到[集算报表安装目录]\report\lib下。

           除了可以直接访问HDFS的文本文件外,集算报表也可以读取HDFS中的压缩文件。这时仍然使用hdfsfile函数,由扩展名决定解压方式。比如,要访问Gzip文件可以这样写:

    =hdfsfile("hdfs://192.168.1.210:9000/usr/local/hadoop/data/stock_record_"+d_date+".gz","GBK"),只需在将扩展名包含在url中即可。

            

           通过上面的实现可以看到,使用集算器脚本可以很方便地完成HDFS文件的读取计算,而且外置的集算脚本具有可视化的编辑调试环境,编辑好的脚本还可以复用(被其他报表或程序调用)。不过,如果脚本已经调试好,而且不需要复用的时候,要维护两个文件(集算脚本和报表模板)的一致性会比较麻烦,这时候直接使用集算报表的脚本数据集就比较简单了。

           在脚本数据集中可以分步编写脚本完成计算任务,语法与集算器一致,还可以直接使用报表定义好的数据源(本例并未涉及)和参数。使用脚本数据集可以这样完成:

            1.  在数据集设置窗口中点击“增加”按钮,弹出数据集类型对话框,选择“脚本数据集”;

            2.      在弹出的脚本数据集编辑窗口中编写脚本;

            直接使用报表定义的参数arg1。

            3.报表参数设置和报表表达式,与使用集算器数据集一致,不再赘述。

     

           报表部署时,同样需要将Hadoop的相关jar放到应用classpath下,如应用的web-inf\lib下。


    集算报表下载:http://www.raqsoft.com.cn/?p=208


    展开全文
  • 在Java开发的报表工具FineReport中,假如在目录下保存了几个XML文件,希望把XML文件转换为报表数据,同时希望展示动态xml数据的效果,这时可通过参数的方式,动态获取xml字段中的值再作为报表数据。...

    在Java开发的报表工具FineReport中,假如在目录下保存了几个XML文件,希望把XML文件转换为报表数据源,同时希望展示动态xml数据源的效果,这时可通过参数的方式,动态获取xml字段中的值再作为报表数据源。

    Northwind.xml记录数据格式如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <Northwind>
        <Customers>
    	    <CustomerID>ALFKI</CustomerID>
    		<CompanyName>ALfreds Futterkiste</CompanyName>
    		<ContactName>Maria Anders</ContactName>
    		<ContactTitle>Sales Representative</ContactTitle>
    		<Address>Obere Str.57</Address>
    		<City>Berlin</City>
    		<PostalCode>12209</PostalCode>
    		<Country>Germany</Country>
    		<Phone>030-0074321</Phone>
    		<Fax>030-0076545</Fax>
    	</Customers>
    </Northwind>

    最终用于制作报表的数据源形式如下:


    对于这样的情况我们如何来实现呢?FineReport中可以通过自定义程序数据集来对xml字段数据进行解析,最终返回所希望的数据表。实现步骤如下:

    1、  定义XMLColumnNameType4Demo封装类

    首先定义参数name及type,供其他类直接调用,安全性比较高,详细代码如下:

    package com.fr.data;  
      
    public class XMLColumnNameType4Demo {  
        private int type = -1;  
        private String name = null;   
        public XMLColumnNameType4Demo(String name, int type) {  
            this.name = name;  
            this.type = type;  
        }  
        public String getName() {  
            return name;  
        }  
        public void setName(String name) {  
            this.name = name;  
        }      
        public int getType() {  
            return type;  
        }  
        public void setType(int type) {  
            this.type = type;  
        }  
    }
    
    

    2、定义XMLParseDemoDataModel.java类文件

    定义XMLParseDemoDataModel.java类继承AbstractDataModel接口,实现getColumnCount、getColumnName、getRowCount、getValueAt四个方法,详细代码如下:

    package com.fr.data;  
      
    import java.io.File;  
    import java.util.ArrayList;  
    import java.util.List;  
    import javax.xml.parsers.SAXParser;  
    import javax.xml.parsers.SAXParserFactory;  
    import org.xml.sax.Attributes;  
    import org.xml.sax.SAXException;  
    import org.xml.sax.helpers.DefaultHandler;  
    import com.fr.base.FRContext; 
    import com.fr.data.AbstractDataModel;  
    import com.fr.general.ComparatorUtils;
    import com.fr.general.data.TableDataException;
      
    /** 
     * XMLParseDemoDataModel 
     *  
     * DataModel是获取数据的接口 
     *  
     * 这里通过init方法一次性取数后,构造一个二维表对象来实现DataModel的各个取数方法 
     */  
    public class XMLParseDemoDataModel extends AbstractDataModel {  
        // 数据类型标识  
        public static final int COLUMN_TYPE_STRING = 0;  
        public static final int COLUMN_TYPE_INTEGER = 1;  
        public static final int COLUMN_TYPE_BOOLEAN = 2;  
      
        // 缓存取出来的数据  
        protected List row_list = null;  
      
        // 数据对应的节点路径  
        private String[] xPath;  
        // 节点路径下包含的需要取数的节点  
        private XMLColumnNameType4Demo[] columns;  
      
        private String filePath;  
      
        public XMLParseDemoDataModel(String filename, String[] xPath,  
                XMLColumnNameType4Demo[] columns) {  
            this.filePath = filename;  
            this.xPath = xPath;  
            this.columns = columns;  
        }  
      
        /** 
         * 取出列的数量 
         */  
        public int getColumnCount() throws TableDataException {  
            return columns.length;  
        }  
      
        /** 
         * 取出相应的列的名称 
         */  
        public String getColumnName(int columnIndex) throws TableDataException {  
            if (columnIndex < 0 || columnIndex >= columns.length)  
                return null;  
            String columnName = columns[columnIndex] == null ? null  
                    : columns[columnIndex].getName();  
      
            return columnName;  
        }  
      
        /** 
         * 取出得到的结果集的总的行数 
         */  
        public int getRowCount() throws TableDataException {  
            this.init();  
            return row_list.size();  
        }  
      
        /** 
         * 取出相应位置的值 
         */  
        public Object getValueAt(int rowIndex, int columnIndex)  
                throws TableDataException {  
            this.init();  
            if (rowIndex < 0 || rowIndex >= row_list.size() || columnIndex < 0  
                    || columnIndex >= columns.length)  
                return null;  
            return ((Object[]) row_list.get(rowIndex))[columnIndex];  
        }  
      
        /** 
         * 释放一些资源,取数结束后,调用此方法来释放资源 
         */  
        public void release() throws Exception {  
            if (this.row_list != null) {  
                this.row_list.clear();  
                this.row_list = null;  
            }  
        }  
      
        /** ************************************************** */  
        /** ***********以上是实现DataModel的方法*************** */  
        /** ************************************************** */  
      
        /** ************************************************** */  
        /** ************以下为解析XML文件的方法**************** */  
        /** ************************************************** */  
      
        // 一次性将数据取出来  
        protected void init() throws TableDataException {  
            if (this.row_list != null)  
                return;  
      
            this.row_list = new ArrayList();  
            try {  
                // 使用SAX解析XML文件, 使用方法请参见JAVA SAX解析  
                SAXParserFactory f = SAXParserFactory.newInstance();  
                SAXParser parser = f.newSAXParser();  
      
                parser.parse(new File(XMLParseDemoDataModel.this.filePath),  
                        new DemoHandler());  
            } catch (Exception e) {  
                e.printStackTrace();  
                FRContext.getLogger().error(e.getMessage(), e);  
            }  
        }  
      
        /** 
         * 基本原理就是解析器在遍历文件时 发现节点开始标记时,调用startElement方法 读取节点内部内容时,调用characters方法 
         * 发现节点结束标记时,调用endElement 
         */  
        private class DemoHandler extends DefaultHandler {  
            private List levelList = new ArrayList(); // 记录当前节点的路径  
            private Object[] values; // 缓存一条记录  
            private int recordIndex = -1; // 当前记录所对应的列的序号,-1表示不需要记录  
      
            public void startElement(String uri, String localName, String qName,  
                    Attributes attributes) throws SAXException {  
                // 记录下  
                levelList.add(qName);  
      
                if (isRecordWrapTag()) {  
                    // 开始一条新数据的记录  
                    values = new Object[XMLParseDemoDataModel.this.columns.length];  
                } else if (needReadRecord()) {  
                    // 看看其对应的列序号,下面的characters之后执行时,根据这个列序号来设置值存放的位置。  
                    recordIndex = getColumnIndex(qName);  
                }  
            }  
      
            public void characters(char[] ch, int start, int length)  
                    throws SAXException {  
                if (recordIndex > -1) {  
                    // 读取值  
                    String text = new String(ch, start, length);  
                    XMLColumnNameType4Demo type = XMLParseDemoDataModel.this.columns[recordIndex];  
                    Object value = null;  
                    if (type.getType() == COLUMN_TYPE_STRING) {  
                        value = text;  
                    }  
                    if (type.getType() == COLUMN_TYPE_INTEGER) {  
                        value = new Integer(text);  
                    } else if (type.getType() == COLUMN_TYPE_BOOLEAN) {  
                        value = new Boolean(text);  
                    }  
      
                    values[recordIndex] = value;  
                }  
            }  
      
            public void endElement(String uri, String localName, String qName)  
                    throws SAXException {  
                try {  
                    if (isRecordWrapTag()) {  
                        // 一条记录结束,就add进list中  
                        XMLParseDemoDataModel.this.row_list.add(values);  
                        values = null;  
                    } else if (needReadRecord()) {  
                        recordIndex = -1;  
                    }  
                } finally {  
                    levelList.remove(levelList.size() - 1);  
                }  
            }  
      
            // 正好匹配路径,确定是记录外部的Tag  
            private boolean isRecordWrapTag() {  
                if (levelList.size() == XMLParseDemoDataModel.this.xPath.length  
                        && compareXPath()) {  
                    return true;  
                }  
      
                return false;  
            }  
      
            // 需要记录一条记录  
            private boolean needReadRecord() {  
                if (levelList.size() == (XMLParseDemoDataModel.this.xPath.length + 1)  
                        && compareXPath()) {  
                    return true;  
                }  
      
                return false;  
            }  
      
            // 是否匹配设定的XPath路径  
            private boolean compareXPath() {  
                String[] xPath = XMLParseDemoDataModel.this.xPath;  
                for (int i = 0; i < xPath.length; i++) {  
                    if (!ComparatorUtils.equals(xPath[i], levelList.get(i))) {  
                        return false;  
                    }  
                }  
      
                return true;  
            }  
      
            // 获取该字段的序号  
            private int getColumnIndex(String columnName) {  
                XMLColumnNameType4Demo[] nts = XMLParseDemoDataModel.this.columns;  
                for (int i = 0; i < nts.length; i++) {  
                    if (ComparatorUtils.equals(nts[i].getName(), columnName)) {  
                        return i;  
                    }  
                }  
      
                return -1;  
            }  
        }  
    }
    

    3、定义程序数据集XMLDemoTableData

    通过参数filename,动态显示xml文件内容,首先xml文件需要放到某个目录下,如下代码是放到D盘,并且定义需要解析的数据列,这边定义的数据列名称,根xml内字段名称是一一对用的。详细代码如下:

    packagecom.fr.data;   
     
    importjava.io.BufferedInputStream; 
    importjava.io.ByteArrayInputStream; 
    importjava.io.File; 
    importjava.io.FileInputStream; 
    importjava.io.FileNotFoundException; 
    importjava.io.FileReader; 
    importjava.io.InputStream; 
    importjava.io.Reader; 
    importjava.util.*;
     
    importjavax.xml.stream.XMLEventReader; 
    importjavax.xml.stream.XMLInputFactory; 
    importjavax.xml.stream.XMLStreamException; 
    importjavax.xml.stream.events.XMLEvent;
     
    importcom.fr.base.Parameter; 
    importcom.fr.data.AbstractParameterTableData;
    importcom.fr.general.data.DataModel;
    importcom.fr.script.Calculator;   
    importcom.fr.stable.ParameterProvider;
    importcom.fr.stable.StringUtils;
       
    /** 
     * XMLDemoTableData 
     *  
     *  这是一个按参数来解析不同地址XML文件的demo 
     *  
     * AbstractParameterTableData 包装了有参数数据集的基本实现 
     */   
    publicclass XMLDemoTableData extends AbstractParameterTableData {   
           
        // 构造函数   
        public XMLDemoTableData() {   
            // 定义需要的参数,这里定义一个参数,参数名为filename,给其一个默认值"Northwind.xml"   
            this.parameters = newParameter[1];   
            this.parameters[0] = newParameter("filename", "Northwind");    
        }   
       
        /** 
         * 返回获取数据的执行对象 
         * 系统取数时,调用此方法来返回一个获取数据的执行对象 
         * 注意!当数据集需要根据不同参数来多次取数时,此方法在一个计算过程中会被多次调用。 
         */   
       @SuppressWarnings("unchecked") 
        public DataModel createDataModel(Calculatorcalculator) {   
            // 获取传进来的参数   
            ParameterProvider[] params =super.processParameters(calculator);   
               
            // 根据传进来的参数,等到文件的路径   
            String filename = null;   
            for (int i = 0; i < params.length;i++) {   
                if (params[i] == null)continue;   
                   
                if("filename".equals(params[i].getName())) {   
                    filename =(String)params[i].getValue();   
                }   
            }   
               
            String filePath;   
            if (StringUtils.isBlank(filename)){   
                filePath ="D://DefaultFile.xml";   
            } else {   
                filePath = "D://" +filename + ".xml";   
            }   
               
            // 定义需要解析的数据列,机器   
    //        XMLColumnNameType4Demo[] columns = newXMLColumnNameType4Demo[7];   
    //        columns[0] = newXMLColumnNameType4Demo("CustomerID",XMLParseDemoDataModel.COLUMN_TYPE_STRING);   
    //        columns[1] = newXMLColumnNameType4Demo("CompanyName",XMLParseDemoDataModel.COLUMN_TYPE_STRING);   
    //        columns[2] = newXMLColumnNameType4Demo("ContactName",XMLParseDemoDataModel.COLUMN_TYPE_STRING);   
    //        columns[3] = newXMLColumnNameType4Demo("ContactTitle",XMLParseDemoDataModel.COLUMN_TYPE_STRING);   
    //        columns[4] = newXMLColumnNameType4Demo("Address",XMLParseDemoDataModel.COLUMN_TYPE_STRING);   
    //        columns[5] = newXMLColumnNameType4Demo("City",XMLParseDemoDataModel.COLUMN_TYPE_STRING);   
    //        columns[6] = new XMLColumnNameType4Demo("Phone",XMLParseDemoDataModel.COLUMN_TYPE_STRING);   
               
            List list=new ArrayList(); 
            XMLInputFactory inputFactory =XMLInputFactory.newInstance(); 
            InputStream in; 
            try { 
                in = new BufferedInputStream(newFileInputStream(new File(filePath))); 
                XMLEventReader reader =inputFactory.createXMLEventReader(in); 
                readCol(reader,list); 
                in.close(); 
            } catch (Exception e) { 
                // TODO Auto-generated catchblock 
                e.printStackTrace(); 
            } 
            XMLColumnNameType4Demo[]columns=(XMLColumnNameType4Demo[])list.toArray(newXMLColumnNameType4Demo[0]); 
             
             
            // 定义解析的数据在xml文件结构中的位置   
            String[] xpath = new String[2];   
            xpath[0] = "Northwind";   
            xpath[1] = "Customers";   
            /* 
             * 说明 
             * 提供的样例xml文件的格式是: 
             * <Notrhwind> 
             *    <Customers> 
             *         <CustomerID>ALFKI</CustomerID> 
             *         <CompanyName>AlfredsFutterkiste</CompanyName> 
             *         <ContactName>MariaAnders</ContactName> 
             *         <ContactTitle>SalesRepresentative</ContactTitle> 
             *         <Address>Obere Str. 57</Address> 
             *         <City>Berlin</City> 
             *        <PostalCode>12209</PostalCode> 
             *        <Country>Germany</Country> 
             *        <Phone>030-0074321</Phone> 
             *        <Fax>030-0076545</Fax> 
             *    </Customers> 
             * </Northwind> 
             *  
             * 上面定义的意义就是 
             * /Northwind/Customers路径所表示的一个Customers节点为一条数据,它包含的节点中的CustomerID...等等是需要获取的列值 
             */   
               
            // 构造一个实际去取值的执行对象   
            return new XMLParseDemoDataModel(filePath,xpath, columns);   
        } 
        private int deep=0; 
        private static final int COL_DEEP=3; 
        private boolean flag=false; 
        private void readCol(XMLEventReader reader,List list) 
                throws XMLStreamException { 
            while (reader.hasNext()) { 
                XMLEvent event =reader.nextEvent(); 
                if (event.isStartElement()) { 
                    //deep是控制层数的,只把xml中对应的层的加入到列名中 
                    deep++; 
                    //表示已经进入到了列名那一层 
                    if(deep==COL_DEEP){ 
                        flag=true; 
                    } 
                    //如果在高层,并且已经进入到了col层,则退出 
                   if(deep<COL_DEEP&&flag){ 
                        return; 
                    } 
                    if(deep!=COL_DEEP){ 
                        continue; 
                    } 
    //              println("name: " +event.asStartElement().getName()); 
                    XMLColumnNameType4Democolumn=new XMLColumnNameType4Demo(event.asStartElement().getName().toString(),XMLParseDemoDataModel.COLUMN_TYPE_STRING); 
                    list.add(column); 
                    readCol(reader,list); 
                } else if (event.isCharacters()){ 
                    //对数据值不做处理 
                } else if (event.isEndElement()){ 
                    deep--; 
                    return; 
                } 
            } 
        } 
         
        private void readCol0(XMLEventReader reader) 
                throws XMLStreamException { 
            while (reader.hasNext()) { 
                XMLEvent event = reader.nextEvent(); 
                if (event.isStartElement()) { 
                    //deep是控制层数的,只把xml中对应的层的加入到列名中 
                    deep++; 
                    //表示已经进入到了列名那一层 
                    if(deep==COL_DEEP){ 
                        flag=true; 
                    } 
                    //如果在高层,并且已经进入到了col层,则退出 
                   if(deep<COL_DEEP&&flag){ 
                        return; 
                    } 
                    if(deep!=COL_DEEP){ 
                        continue; 
                    } 
                    System.out.println("name:" + event.asStartElement().getName()); 
                    readCol0(reader); 
                } else if (event.isCharacters()){ 
                    //对数据值不做处理 
                } else if (event.isEndElement()){ 
                    deep--; 
                    return; 
                } 
            } 
        } 
        public static void main(String[]args){ 
            XMLInputFactory inputFactory =XMLInputFactory.newInstance(); 
    //      in = new FileReader(newFile(filePath)); 
    //      XMLEventReader reader = inputFactory.createXMLEventReader(in); 
    //      readCol(reader,list); 
            BufferedInputStream in; 
            try { 
                in = new BufferedInputStream(newFileInputStream(new File("D:/tmp/f.xml"))); 
                byte[] ba=new byte[3]; 
                in.read(ba,0,3); 
    //      System.out.println(in) 
            XMLEventReader reader =inputFactory.createXMLEventReader(in); 
            newXMLDemoTableData().readCol0(reader); 
            } catch (Exception e) { 
                    // TODO Auto-generated catchblock 
                    e.printStackTrace(); 
                } 
        } 
    }

    注:如果xml文件的格式上问题描述处所展示的xml格式不一致,则需要修改类中的deep变量,把列名所在的节点层数改成相对应的数值。

    注:XMLDemoTableData里面的filename并不是文件名,而是xml里面某个标签名。

    4、编译程序数据源

    分别编译XMLColumnNameType4Demo.java、XMLParseDemoDataModel.java、XMLDemoTableData.java三个类文件,将生成的class文件放于%FR_HOME%\WebReport\WEB-INF\classes\com\fr\data下。

     

    5 配置程序数据源

    新建报表,模板数据集>程序数据集,选择我们定义好的程序数据集XMLDemoTableData.class文件,名字可以自定义,如程序1。



    6、使用程序数据源

    在模板数据集窗口,点击预览按钮,弹出参数对话框,输入要显示的xml文件名称,点击确定则可以把Northwind.xml文件里面的数据读取出来转换报表数据源了,如下图:


    展开全文
  • 报表数据之多结果集

    千次阅读 2015-04-17 13:34:54
    多样性数据报表开发中越来越常见,润乾集算报表对多样性数据的有效支持使得这类报表开发变得非常简单,目前集算报表除了支持不同类型的数据(RDB、TXT文本、Excel、JSON、HTTP、Hadoop、mongodb)外,还支持...

           多样性数据源在报表开发中越来越常见,润乾集算报表对多样性数据源的有效支持使得这类报表开发变得非常简单,目前集算报表除了支持不同类型的数据源(RDB、TXT文本、Excel、JSON、HTTP、Hadoop、mongodb)外,还支持在一个数据集中为报表返回多个结果集使用,这样可以有效避免重复运算,提升报表开发效率和运算性能。下面通过一个实例说明多结果集的使用过程。

    报表说明

           根据学生成绩表查询总成绩前三名和后三名的学生姓名以及总成绩。报表样式如下:


           由于要分别显示前三名和后三名学生姓名和成绩,报表自然地分成了两部分。这两部分数据如果使用一个数据集会需要隐藏格辅助,使用两个数据集则比较简单,一个数据集基于原始数据进行分组汇总、按总成绩降序排序后取前三名,第二个数据集按升序取前三名。但这个过程又会发生重复计算(分组汇总和排序),通过集算器返回多结果集则不会有这个问题。下面是实现过程。

    编写集算脚本

           使用集算脚本编辑器编写计算脚本,完成数据计算及数据源准备工作。


           A1:连接数据源demo;

           A2:执行sql查询学生成绩表数据;

           A3:按照学生分组,汇总成绩;

           A4:使用A.top()函数按照总成绩取前三条记录;

           A5:使用A.top()函数按照总成绩取后三条记录;

           A6:将前后三名记录以两个结果集返回。

    编辑报表模板

           连接报表数据源demo。

    设置数据集

           使用集算报表设计器新建报表模板,并设置集算器数据集,调用上面编辑好的脚本。由于脚本中返回2个结果集,在数据集设置中,需要手动填写数据集名称为“ds1,ds2”,多个数据集名称之间以逗号分隔。


           其中,dfx文件路径既可以是绝对路径,也可以是相对路径,相对路径是相对选项中配置的dfx主目录的。

    数据集展现形式:

    设置报表表达式

           编辑报表表达式,直接使用集算脚本返回的2个结果集,使用简单的列表表达式,完成报表制作。

           可以看到,使用集算器脚本可以为报表输出多个结果集,而且外置的集算脚本具有可视化的编辑调试环境,编辑好的脚本还可以复用(被其他报表或程序调用)。不过,如果脚本已经调试好,而且不需要复用的时候,要维护两个文件(集算脚本和报表模板)的一致性会比较麻烦,这时候直接使用集算报表的脚本数据集就比较简单了。

           在脚本数据集中可以分步编写脚本完成计算任务,语法与集算器一致,还可以直接使用报表定义好的数据源和参数。使用脚本数据集可以这样完成:

           1.  在数据集设置窗口中点击“增加”按钮,弹出数据集类型对话框,选择“脚本数据集”;

           2.  在弹出的脚本数据集编辑窗口中编写脚本。

           在脚本数据集中直接使用报表定义的数据源demo进行查询,而不必像独立的集算脚本一样必须使用connect()函数连接数据源。

     

           报表表达式与使用集算器数据集方式一致,不再赘述。



    展开全文
  • DevExpress.XtraReports报表,动态设置报表布局 引言 上回负责报表这块,说不能再像以前的项目一样的做报表了,以前项目300多张报表,一张一张的画,一张一张的写存储过程,工作量大啊,当然现在的项目...
  • 本人菜鸟,这篇文章纯属个人记录,主要功能是通过 java 和 Ireport 生成报表,并生成 pdf,word,excel 格式IReport 使用记录教程–原创一、创建主报表1. 主报表属性设置报表下面有多个子报表组成 (A4:: 842*595)...
  • 主子报表多数据的处理

    千次阅读 2015-07-31 08:56:23
    JasperReport/Birt等报表工具从功能上可以处理,但在子报表中无法直接使用数据名,需要使用显式的数据库账号、口令。可以看到这种方式存在一定的安全隐患,而且实施过程比较复杂。  集算器具有结构化强计算...
  • Crystal 水晶报表的数据

    千次阅读 2014-04-01 18:25:53
    背景知识: 1. 水晶报表主要用于设计和产生报表, 很多企业级系统都可以拿来集成,使得系统数据展示给客户 ...本文记录一下水晶报表的数据配置(1,2,3) ReportClientDocument clientDoc = new ReportClientDocumen
  • 合并报表优化记录

    千次阅读 2013-02-28 13:38:51
    这是早期的合并报表优化记录,内容不多,保留下来备查。 一.查找源报表是否存在 SELECT 1 WHERE EXISTS (SELECT * FROM T_CSL_CslReport WHERE FSourceRptID = '4583062d-010a-1000-e002-63bbc0a8ef02B712EA2C...
  • 报表系统中有部分报表需要按照一定规则显示数据,如:显示查询日期范围内的奇数日数据,要求数据库中即使无记录该日期也显示(内容为空)。
  • FastReport.Net报表经验记录

    千次阅读 2013-08-02 16:18:26
    当打印预览时数据区不显示或只显示一条记录时,是因为在设计报表时数据区没有指定完整的数据
  • 实际业务中经常有一些报表数据来源于文件而非数据库,如:计算应发工资报表用到考勤数据文件、用户行为分析类报表用到的日志文件、股票分析类报表用到的股票交易记录文件等。由于报表一般都带有参数,经常需要对原始...
  • 这类报表由于无法事先确定列数,因而无法在报表中使用固定列的表达式,而且更加棘手的是报表数据的准备,因为SQL不支持不定列的结果集,需要动态拼出SQL语句去执行,有时业务逻辑并不很简单,还需要使用存储过程...
  • 报表工具的动态数据实现

    千次阅读 2015-06-19 10:00:25
    有时候我们需要用参数动态指定数据,或将多数据连接为单数据,或向子报表、table控件动态传入数据名。对于此类需求,报表工具经常要借助高级语言实现或牺牲安全性以降低复杂度,尤其是BIRT、Jasper等单源...
  • 最近改造一个小型购物网站,要求使用水晶报表实现订单打印,本人对水晶报表从一无所知到,到最终弄出来整整花了一夜的时间,特此记录下此文和大家共享。 关于水晶报表更详细的介绍建议大家可以参考阿泰的博客:...
  • 自定义数据报表开发的常态

    千次阅读 2014-07-09 16:50:00
    自定义数据集是指报表的数据不能通过简单SQL实现,需要用报表工具提供的API,调用程序员开发的程序来实现。这部分报表数量不多,但是编程、调试工作量较大,在整个项目中占用的时间反而更长。 为什么自定义数据...
  • 1.6报表设置 工作流报表实现工作流模块数据的简单统计,可以将统计数据以列表模式或者图形化展示。 A、新建报表 报表名称:报表的标识(最好不要重复,否则在使用报表时容易混淆)。 统计方式:按分组统计...
  • 有这么一些报表,取数后还需要进行一定计算后才能供报表展现输出,这要求报表工具具有数据再计算的能力。 传统工具会依赖报表工具自身的计算能力,但报表工具计算能力弱导致很多计算完不成;或者借助存储过程完成...
  • 使用Jasper或BIRT等报表工具时,常会碰到一些非常规的统计,用报表工具本身或SQL都难以处理,比如与主表相关的子表分布在多个数据库中,... 主表org在数据Master中,org里每条记录对应的子表在不同的数据中,比
  • 论坛里,http://bbs.csdn.net/topics/390883416中提的问题,其目的是为了实现一个固定行列的交叉...这里就以链接中业务为背景,给出集算报表实现某种固定列交叉报表的方案。 报表背景  数据如下:  现需要
  • 项目中省公司配置完成...现在需要开发一个分运输方式的完成量的饼状图,但是分运输方式的完成量在结果集的一条记录中,故不能使用group生成饼状图的数据报表上也有四种运输方式的合计量,觉得直接从报表里直接取
  • 复杂数据报表开发的常见问题,比如不同数据库表先进行join运算,再进行后续的过滤分组排序等运算。JasperReport/Birt等报表工具有virtual data source或table join,可以一定程度地实现多数据join后计算,但...
  • 项目中报表的基本设置

    千次阅读 2006-05-30 19:57:00
    页边距设置a) 上边距2.74或2.54 下边距2.74或2.54b) 左边距及右边距根据页面视情况而定,最多不超过1.96数据库连接a) 连接驱动(略)b) 可用SQL命令、表、视图,给报表加载数据源报表设置报表页眉/报表页脚:...
  • oracle数据报表sql计算慢&解决

    千次阅读 2013-12-09 10:08:54
    项目里有些报表出来的速度特别慢,尽管对润乾报表和Oracle数据库做了很多优化,效果还是不理想,这些报表普遍数据量比较大,涉及到的数据库表多(几十张)、表间关联频繁(还有自连接),报表里也有多个汇总、比值等...
  • 今天做的报表涉及到一个报表里使用3个数据表,如何将这三个表的数据映射到fastreport中呢,看下面代码。对应的要在fastreport中将表改成这个名字,数据库连接信息就可以不用保存到报表中了。
  • ADO记录集和水晶报表

    千次阅读 2002-12-03 08:53:00
    那就是使用数据定义文件(TTX),把得到的ADO记录集传送给水晶报表。通常情况下,水晶报表是从物理的数据库上创建出来的,但是现在有了32位的Active Data Driver-- P2smon.dll,水晶就可以不用再事先连接到一个...
  • 今天做的一个复杂报表,涉及到使用2个数据,其中一个读取一条记录在页面显示,另外一个读取关联数据将多条记录在页面中间显示。可以直接在Data band中添加子数据只能在页面最下面显示循环记录。经过简单的探索发现...
  • 水晶报表 代码控制记录排序专家

    千次阅读 2010-06-02 23:03:00
     或许有人会问,记录排序专家直接在 <br />这个界面中控制就好了,可以添加多个排序字段(优先级从上往下递减),为什么还要用代码控制?    没错,完全可以在这个界面中进行控制,但是这样...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 36,741
精华内容 14,696
关键字:

如何设置报表的记录源