您的位置:首页 > Web前端 > HTML

html table to Excel(1)

2012-12-04 15:48 330 查看
转载连接:http://www.fengfly.com/plus/view-197341-1.html

最近做一个小的报表系统,功能本身没什么。最后客户要求一个打印功能,所谓打印,就是按照页面上报表的样子,一模一样的为其生成Excel文件。

  再也不想为了构造结构一样的Excel表格而再次考虑繁琐数据逻辑了!于是乎冒出了这样的一个想法:我要是能获得页面上的报表table,那么只要分析其结构,不就可以构造出相应的Excel表格来吗?

  思来想去,觉得这应该是一条可以走的通的路,于是便着手寻找实现的办法。终于,发现WebRequest和WebResponse,其分别代表一个Web请求和服务器基于请求的回应,而这个回应包含服务器返回的数据流,从数据流便可获取想要的报表table。

  整个Excel生成功能的思路如下图所示:



  涉及WebRequest、WebResponse的核心代码如下:

1 WebRequest wr = WebRequest.Create(psUrl);

2 HttpWebRequest oRequest = wr as HttpWebRequest;

3 if (null == oRequest) return null;

4

5 HttpWebResponse oResponse ;= (HttpWebResponse)
oRequest.GetResponse();

6 string sResponseContent = string.Empty;

7 if (oResponse.StatusCode == HttpStatusCode.OK)

8 {

9 using (StreamReader sr = new StreamReader(oResponse.GetResponseStream(),Encoding.UTF8))

10 {

11 sResponseContent = sr.ReadToEnd(); //sResponseContent,保存了服务器返回的数据流字符串内容

12 sr.Close();

13 }

14 }

15 oResponse.Close();

  特别需要说明的是,在从数据流向字符串转化的过程中,其内会残留许多\r\t之类的转义字符,我们需要将其剔除。

1 sResponseContent = Regex.Replace
(sResponseContent, "[\n\r\t] ", "");

  本篇至此,下篇将着重介绍table到Excel cell的转化过程。

 在上一篇文章中,已经解决了如何获取html table结构的问题。在本篇文章中,我们着力于table结构的解析。

  Html table的结构我们大家都很熟悉,那么在另一端如何构造一个结构,让Excel可以很好的接受和处理呢?

  直观的看,一个完整Excel的内容是由位于各个单元格(Cell)中的内容组合而成的。而每个单元格(Cell)都有相应X、Y坐标来标示其位置。也就是说,一个Excel文件实质上就是许多Cell构成的集合,每个Cell用坐标属性确定位置,用内容属性存储内容。

  基于此,我设计了最基本的Cell结构:

◆ X坐标

◆ Y坐标

◆ 合并列情况

◆ 合并行情况

◆ 内容

  构成Excel的最基本的结构已经确定,下一步摆在我们面前的就是将html table转化为Excel Cell集合。

  Html table中的每个td节点对应一个Excel单元格,其内容不必说,行、列的合并情况也自可由td的rowspan、colspan属性得出,转化的关键点就在于由table的tr td结构定位Excel单元格位置,即X、Y坐标。

  Y坐标容易确定,即td所在tr的行数。至于一td的X坐标,其要受到两方面因素的影响:与该td同处一tr,但位于其之前(反映在表格视觉上即其左侧td)td的占位情况和该td所在tr的之前tr中某些td的跨行情况。

  基于此种考虑,定位td的X坐标需经过两个过程的推导:用于处理左侧td占位影响的横向推导(Horizontal Deduction)和处理之前行跨行td影响的纵向推导(Vertical Deduction)。

  以下图所示table为例,展示两次推导过程。



  横向推导(Horizontal Deduction)

  一次横向推导(Horizontal Deduction)限定在一tr范围内。整个过程基于递归的原理,递归模型如下:



  核心代码为:

1 private int HorizontalDeduction(HtmlNode phnTd)

2 {

3 HtmlNode hnPreviousSibling = phnTd.PreviousSibling;

4 while (hnPreviousSibling != null && hnPreviousSibling.Name != phnTd.Name)

5 {

6 hnPreviousSibling = hnPreviousSibling.PreviousSibling;

7 }

8

9 if (hnPreviousSibling != null)

10 {

11 int nColSpan = hnPreviousSibling.GetAttributeValue("colspan", 1);

12 return HorizontalDeduction(hnPreviousSibling) + nColSpan;

13 }

14

15 return 0;

16 }

  经过横向推导,各td的X、Y坐标如下图所示:



  纵向推导(Vertical Deduction)

  一次纵向推导的过程可以描述为(当前推导td用A表示):

   找到A之前的行tr中与A具有相同X坐标的td节点B

   if (B.rowspan>(A.Y-B.Y))

   {

   X+=B.colspan,即A的X坐标向后推B.colspan的位置

   同时,与A同处一tr但在其后边的td节点均应向后推B.colspan个位移

   }

  对td节点A反复执行这样的一个过程,直到确定A无需再次移动。

  纵向推导核心代码为:

1 bool bActedPush = false;

2

3 do

4 {

5 int nComparedItemIndex = -1;

6 for (int j = i - 1; j >= 0; j--)

7 {

8 if (plstCells[j]._nStartX == oCurrentCell._nStartX)

9 {

10 nComparedItemIndex = j;

11 break;

12 }

13 }

14

15 if (nComparedItemIndex >= 0)

16 {

17 if (plstCells[nComparedItemIndex]._nRowSpan > (oCurrentCell._nStartY - plstCells[nComparedItemIndex]._nStartY))

18 {

19 oCurrentCell._nStartX += plstCells[nComparedItemIndex]._nColSpan;

20

21 bActedPush = true;

22

23 for (int k = i + 1; k < plstCells.Count; k++)

24 {

25 if (plstCells[k]._nStartY == oCurrentCell._nStartY)

26 {

27 plstCells[k]._nStartX += plstCells[nComparedItemIndex]._nColSpan;

28 }

29 }

30 }

31 else

32 {

33 bActedPush = false;

34 }

35 }

36 else

37 {

38 bActedPush = false;

39 }

40 }

41 while (bActedPush);

  以示例table中的four td为例,其经过纵向推导过程后的坐标位置情况如下图:



  关于示例代码的几点说明:

  1、 在示例代码中,我通过一个Config文件对生成的Excel的文件名、其内报表的内容和位置做了一些控制。基本内容如下:

<ExcelDocument>

<BaseInfo>

<FileName>Sample Excel File</FileName> <!--生成Excel的文件名-->

<SheetCount>1</SheetCount> <!--Excel中sheet的数量-->

</BaseInfo>

<Tables>

<ExcelTable>

<TableName>示例表一</TableName> <!--报表名称-->

<WhichSheet>1</WhichSheet> <!--所在sheet的序号-->

<StartX>2</StartX> <!--左上角X坐标-->

<StartY>2</StartY> <!--左上角Y坐标-->

<Source>Sample_Page_1.aspx</Source> <!--table所在页面-->

</ExcelTable>

</Tables>

</ExcelDocument>

  2、 在解析html的过程中,我使用了HtmlAgilityPack解析工具。感兴趣的朋友可以研究一下。地址是这里:http://htmlagilitypack.codeplex.com/。

  3、 HtmlAgilityPack解析html的过程中,其将html标签之间的空隙也会看成是一个节点,为内容为空字符串的文本节点,这点大家应注意。

  4、 该示例代码基本上是一个完整的功能,并且和系统中其他模块耦合度很小。有类似需求的朋友可以拿来直接用。

  附示例代码:ExcelGenerator.rar
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: