Openxml读取和生成简单类型的Excel

      微软的Openxml在2006年底杀出重围,成为那个年代标准之争的胜利者。时至今日,已经有6个年头了。可是遍翻各个博客,涉及到Openxml操作Excel的原创文章屈指可数,而且往往没有深度,所说的东西也都没有说到问题的点子上。

        之所以有上面的抱怨,是因为我最近研究Openxml操作Excel,问题一个接着一个,而且诡异的要命。网上的帖子没有一个说道根儿上的,当然肯定有人敝帚自珍了。其实安装完openxml sdk之后,在开始菜单有一个小程序是很好用的,可以看到某一个Excel的完整生成代码(C#)Microsoft Office Open XML SDK 2.0\Open XML SDK 2.0 Productivity Tool。好了,下面写一下我最近遇到的问题、解决办法和分析(代码就不贴了,没什么意思,下面的分析才算最主要的)

  1. 创建CellRow

这里需要注意的是:Excel中的物理行列存储是按照从上到下、从左到右的规则。而且不创建的行列,在xml中是不存在的。举例来说,我们新建一个空的Excel,此时SheetData节点是空的

我们在B3中填入Hello worldSheetData值如下

 此时我们插入行列必须使用SheetData.InserAt方法插入RowRow.InsertAt方法插入Cell,否则Excel在渲染和呈现的时候会报错(更直白点的说法是:第N行的物理顺序要在N+1行的上面,第X单元格要在X+1单元格的前面)。

  1. 合并单元格


  • 创建第一个MergeCell

这里需要注意的是:创建第一个合并单元格时,往往MergeCells还不存在,所以我们不仅仅要做创建合并单元格的操作,还要负责将MergeCells节点插入到Sheetx.xml中。而此时遇到的问题往往也是因为MergeCells节点在worksheet根节点中的顺序引起的。其正确位置是应在SheetData节点下面,且紧邻SheetData。所以操作的时候应使用Worksheet.InsertAfter方法



  • 解决了Mergecells位置的问题之后,还有一个与合并单元格相关的问题

如果我们按照Openxml自带的sdk中的demo的话,合并C1:E10后打开Excel会报错,而合并C1:C2却没有问题。

其实sdk自带的demo中给出的是“合并相邻的两个单元格”示例,所以在例子中是没有任何问题的,但是这给人一个误导:只要左上角和右下角的单元格创建了,然后再设置一下MergeCell.Reference = "C1:E10"ok了。错误的原因是合并区域内的单元格必须全部创建,即我们要创建C1:E10区间内的所有单元格,这样问题就解决了。分析到这里,也仅仅是一个表象。根本的原理是:合并单元格只是Excel在呈现时给大家的视觉效果而已,其根本是xml的节点数据



  • sdk自带的demo简单修改后,还会遇到一个问题。假如我们将合并相邻单元格改为A2:A1B2:A2后,打开Excel同样会报错。原因出在MergeCell.Reference

A2:A1   A2:A1"/>

B2:A2   B2:A2"/>

细心的读者,如果注意观察sheetx.xml就会发现上面的两行合并单元格的节点内容,这是打开Excel报错的直接原因。其根本原因是违背了文章之初所指出的物理存储顺序:先上后下、先左后右。所以上面的错误修改后应该是

A2:A1   A1:A2"/>

B2:A2   A2:B2"/>


  1. 向合并的单元格赋值

假如有合并单元格A1:C10,我们要给该合并单元格赋值时,必须并且只能将值赋给A1单元格。其原理也牵扯到sheetx.xml的物理存储结构,就不深入展开。下面是sheetx.xml中合并单元格存储值的截图


  1. 取合并单元格的值

假如有合并单元格A1:C10,我们要取A3的值。

根据上面的描述,真实值是存储在A1单元格中,所以需要通过其它的方式找到合并区域左上角的单元格,并取其值(本例应该A1

 

  1. number类型单元格的值

该类型的单元格的值不是存储在sharedstring中,且节点没有"t"属性,其值是存储在该单元格的InnerText

 

  1. Date类型单元格的值

该类型的单元格的值不是存储在sharedstring中,且节点没有"t"属性,其值是存储在该单元格的InnerText中,Date.ToOADate()的值,所以返回的时候需要转换成Date类型


发个博客真费劲啊,这个格式调整真让人蛋疼!


你可能感兴趣的:(Openxml,Excel)