Web应用中基于XML的Excel报表设计

来源:互联网 发布:钢琴入门自学教程知乎 编辑:程序博客网 时间:2024/04/30 12:11

(本文写于2008年,原本想通过期刊发表,但当时感觉刊登费用过高而放弃发表。)



一 引言
    在基于Web应用的企业信息管理系统中,经常需要将相关数据以Excel文档的方式输出,或打印,或经过二次加工后被其它文档所引用。有两种实现方法:一是在服务器端处理Excel文档,完毕后发送到客户端,在客户端的Excel中打开,另一种方法是在服务器端将数据处理好后发送到客户端,在客户端用脚本打开Excel并装入该数据。后一种方法由于涉及在浏览器中创建一外部对象,要求浏览器设置为较低的安全级别并且需要较复杂的脚本逻辑,因此在多数情况下,第一种方法是首选方法。
    在服务器端处理Excel文档,通常的做法是采用Excel文档对象模型直接操作文档,这种方法要求服务器端安装Excel,操作完成后,由于Excel对象只提供了将结果保存在磁盘上的功能,后续程序必须再从磁盘上读取该文档,再发送到客户端,可以看出,这种方法从安全性(服务器端安装Office软件)和效率上都值得商榷。本文提出采用XML形式而非xls形式Excel文档的方法,支持XML格式是自Excel XP版提供的功能,由于.Net Framework提供了丰富的方法操作XML文档,处理完毕后,可直接发送到客户端,无需安装任何额外的软件,因此这是一种简单易行的报表生产方法。
    多数情况下,用户要求输出的报表格式都已预先确定,可以先制作好这些模板,以XML形式保存在服务器端,在输出时,只需填充数据到对应的单元格,这样,虽然XML文档比较复杂,但制作报表时,只关心如何填充数据即可。
如果不涉及复杂的业务逻辑,计算数据尽量在Excel中通过设置的公式来完成,某些中间结果也可以保存在隐藏列中,以后当报表内容发生小变化时,信息系统管理人员就可以通过修改Excel模板来完成,而不必要求开发人员到场,从而减少了系统维护量。
    由于Excel 2003版全面支持XML形式的载入和输出,是目前最常用的Excel版本,所以本文的分析设计都基于该版本。

 

 XML形式的Excel文档分析

XML形式的Excel文档的结构大致如图1所示,其中(1..n)表示该元素可以重复n次。图中<DocumentProperties><ExcelWorkbook><Style>分别用来设置Excel的文档属性、窗口属性以及文档中所用到的格式信息,本文不必考虑这些元素。<Worksheet>是文档内容的主体,代表一个Excel页,其中<Table>又是<Worksheet>的主体,其属性ExpandedColumnCount ExpandedRowCount分别用来设置非空单元格的最大行、列数。元素<Column>设置列的显示属性,本文不必考虑,元素<Row>代表一行,它的子元素<Cell>代表单元格,单元格的内容在<Data>中,<Data>的属性Type表示单元格内容的数据类型,最常用的类型是String(字符串)Number(数字)。如果单元格是一个公式,以<Cell>的属性Formula表示。

 

1 XML形式的Excel文档的大致结构

为压缩XML文档的大小,出现空行或空单元格时,采用特别的处理方式。

  •  连续空行大于2时,不存储后续的空行信息,第一个空行用属性Span=“n”表示后续还有n个连续空行,紧跟的第一个非空行用属性Index=“m”表示再次的行起始于第m行。
  • 一行内不保存完全为空的单元格。在下一个非空单元格出现时,用属性Index=“n”表示数据再次起始于第n列。

 操作Excel文档

了解XML形式的Excel文档格式,就可以构造出操作此文档的类。作者构造出的操作类如图2所示。

 

2  Excel文档操作类

ExcelCell类与文档中<Cell>元素对应,包含一个XmlNode类和Index属性,代表某行的非空节点,ExcelRow类与<Row>元素对应,包含一个ExcelCell链表、XmlNode类和Index属性。ExcelTable类与<Worksheet>元素对应,维护了一个ExcelRow链表。ExcelCellExcelRow只起到存储数据的作用,实际的操作都在ExcelTable中完成。ExcelXMLHelper类维护了一个ExcelTable链表,提供了操作XML文档的方法,ExcelCellExcelRowExcelTable都是供ExcelXMLHelper内部使用的类。

操作XML文档时,ExcelXMLHelper先读入XML模板,解析其结构,生成ExcelTable链表,每个ExcelTable节点生成ExcelRow链表,每个ExcelRow节点生成ExcelCell链表,每个ExcelCell节点填充<Cell>内容和Index属性,ExcelRow也有Index属性,表明该节点所处位置。

由于文档采用“压缩”结构,填写或修改Excel单元格(已知行、列的Index)内容分3种情况:

  • 根据Index能够查找出ExcelCell对象,表明该单元格已存在,则直接修改其内容;
  • 根据Index只能查找出ExcelRow对象,表明该行存在而单元格不存在,需要在该ExcelRow对象的ExcelCell链表的合适位置创建ExcelCell,视不同情况,设置、修改或删除当前和后面ExcelCell对象中XmlNodeIndex属性
  • 根据Index不能查找出ExcelRow,表明该行和单元格都不存在,需在ExcelTableExcelRow链表的合适位置创建ExcelRow,视不同情况,设置、修改或删除前面、当前和后面ExcelRow对象中XmlNodeIndex属性,再按第二种情况处理。

对于后两种操作,如果添加的行或列序数大于属性ExpandedColumnCountExpandedRowCount的值,则应修改对应的属性。

    为使单元格的赋值使用简洁并符合Excel习惯,XMLExcelHelper类重载了[]操作符,可以直接使用诸如excel[3,“AB”]=1excel[5,6]=“A”等样式的赋值语句,使使用十分整齐。

 

四  实际应用举例

在作者开发的炼铁生产管理系统中,所有需要打印或上报的报表都采用XML形式的Excel文档输出,输出的原始报表模板保存在特定的目录下,当用户需要输出某个报表时,服务器端程序从数据层获得数据,采用上面的操作类将其填入到对应单元格,以XML格式的字符串输出到客户端,同时将Content-type设置为“application/excel”,则客户端自动打开Excel装载接收到的报表。

    3是系统中较复杂的一个报表-炼铁日报,包含了当日几乎所有的生产参数,其中约四分之一是计算数据,通过公式设置产生,有十余个辅助计算的数据保存在“页2”中,一般情况下,用户不关心“页2”的内容。该日报要求每日打印一份,打印前,管理人员偶而会调整有关数据或强调某些指标数据,用Excel处理这种要求是非常方便的。


3  炼铁日报的Excel报表输出


五  结论

Excel提供了载入和输出XML格式文档的功能,也就提供了一种不依赖于Excel对象模型而操作Excel文档的方法。通过分析XML的格式,编写了操作Excel文档的辅助类,将这些类用于企业信息系统中的报表输出,既符合用户的使用习惯,又简化了报表制作,同时提高了服务器的安全性。


原创粉丝点击