使用EPPlus 3.1.2開啟RDLC匯出的xlsx檔,讀取ExcelPackage.Workbook.Worksheets時發生錯誤:
System.ArgumentNullException: Value cannot be null.
Parameter name: String
既然EPPlus是Open Source,照慣例 -- "Use the Source, Luke!"
追進原始碼,找到案發現場 -- ExcelWorksheet.cs LoadColumns(),爆炸點在xr.GetAttribute(“min”)傳回null,導致int.Parse()出錯。
privatevoid LoadColumns (XmlTextReader xr)//(string xml)
{
var colList = new List<IRangeID>();
if (ReadUntil(xr, "cols", "sheetData"))
{
//if (xml != "")
//{
//var xr=new XmlTextReader(new StringReader(xml));
while(xr.Read())
{
if(xr.LocalName!="col") break;
int min = int.Parse(xr.GetAttribute("min"));
int style;
if (xr.GetAttribute("style") == null ||
!int.TryParse(xr.GetAttribute("style"), out style))
{
style = 0;
}
ExcelColumn col = new ExcelColumn(this, min);
//...略...
追查RDLC匯出xlsx檔中的sheet1.xml,其中<cols><col>結構如下:
<sheetViews>
<sheetViewworkbookViewId="0"showGridLines="0">
</sheetView>
</sheetViews>
<cols>
<colmin="1"max="1"customWidth="1"width="10.3515625">
</col>
<colmin="2"max="2"customWidth="1"width="78.79296875">
</col>
</cols>
<sheetData>
<rowr="1"ht="17"customHeight="0">
經過一番推敲,錯誤源自<col>與</col>會觸發兩次xr.Read(),第二次讀入</col>時,因屬於EndElement,xr.GetAttribute()讀不到東西,故傳回null。猜想這段寫法平日之所以運作正常,是因為絕大部分xlsx都採用<col min="1" … /> Self-Closing Tag形式,而RDLC匯出xlsx時採取較罕見的<col></col>寫法,踩中地雷而爆炸。(Excel開檔OK,應算EPPlus的Bug)
找到原因,要解決就不是難事,在xr.Read()後,加入一行避開</col>,藥到病除! (當然,也回報到CodePlex囉~)
while(xr.Read())
{
//2012-12-06 by Jeffrey Lee, to ignore </col> End Element
if (xr.NodeType == XmlNodeType.EndElement) continue;
if(xr.LocalName!="col") break;