2016-01-22 89 views
1

我在c sharp中運行了一些基於openXML的代碼,這些代碼卡在第一行數據上並且一次又一次地循環。我很清楚,我需要將行變量合併到混合中,但嘗試過各種方法無濟於事。任何人有任何想法呢?從電子表格中讀取OpenXML卡在第一行

在下面的代碼塊中,sst.ChildElements [7] .InnerText獲取第一行第7列的內容,但每次循環它的內容都來自同一個CELL!我想移動到下一行:-(

string fileName = @"c:\temp\accountData.xlsx"; 

using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
{ 
    using (SpreadsheetDocument doc = SpreadsheetDocument.Open(fs, false)) 
    { 
     WorkbookPart workbookPart = doc.WorkbookPart; 
     SharedStringTablePart sstpart = workbookPart.GetPartsOfType<SharedStringTablePart>().First(); 
     SharedStringTable sst = sstpart.SharedStringTable; 

     WorksheetPart worksheetPart = workbookPart.WorksheetParts.First(); 
     Worksheet sheet = worksheetPart.Worksheet; 

     var cells = sheet.Descendants<Cell>(); 
     var rows = sheet.Descendants<Row>(); 

     Console.WriteLine("Row count = {0}", rows.LongCount()); 
     Console.WriteLine("Cell count = {0}", cells.LongCount()); 

     CompanyProvider cp = _db.GetCompanyProvider(); 
     int i = 0; 

     // Or... via each row 
     foreach (Row row in rows.ToList()) 
     { 
      if (i == 0) 
       i = i + 1; 
      else 
      { 
       CustomerAddress customerAddress = new CustomerAddress(); 
       customerAddress.AddressLine1 = sst.ChildElements[7].InnerText; // Code hidden for brevity 

       i = i + 1; 
      } 
     } 
    } 
} 
+0

你有一個foreach,但你從不使用行對象。爲什麼? – SergeyAn

+0

我使用行對象進行的任何嘗試都無法使其工作。 row.Elements可能是開始,但無法獲得我需要的表達式。我想通過0,1,2,3,4列中的每一列逐行引用列,因此我可以在db中填充字段。示例所有循環單元格 – John

+0

是否所有單元格都填充在電子表格中?例如,如果你有一行空的第一個單元格,那麼'ChildElements [7]'將是第8個單元格。您也可以使用'foreach(row.Skip(1).ToList())行'而不是整數檢查 –

回答

0

在下面的代碼塊,sst.ChildElements [7] .InnerText回來的第一行第7列中但每次RO的含有w循環來自同一個CELL的內容!

這是因爲你總是從閱讀中SharedStringsTable(您sst變量)元素7的價值,而不是從元件7在(您row變量)的值。

共享字符串表是OpenXML中用來防止重複數據出現在單元格中(以減小文件大小)的一種機制。而不是直接包含字符串值的單元格,而是可以包含一個整數,該整數是共享字符串表中的索引。這樣,如果一個字符串在一個Excel文件中重複多次,它只會被存儲一次,但對該字符串有很多引用。

你可以告訴一個Cell對象是否包含一個共享字符串指數通過查看其DataType屬性(注意,字符串可以存儲在網上和其他數據類型,如數字總是存儲在行)。

如果電池確實持有共享字符串索引,那麼你可以使用值索引你sst屬性來獲得正確的內容:

sst.ChildElements[<cell content here>].InnerText 

要獲得行細胞指標,你可以抓住孩子Cell S中後的使用Enumerable<T>.ElementAt方法來獲取Cell指數在你需要:

row.Elements<Cell>().ElementAt(7); //gives the 8th Cell in row - read the "HOWEVER" section!! 

我們荷蘭國際集團上面,你會foreach然後變成類似:

foreach (Row row in rows.ToList()) 
{ 
    if (i == 0) 
     i = i + 1; 
    else 
    { 
     //get the cell at index 7 
     Cell cell = row.Elements<Cell>().ElementAt(7); //read the warning below 

     //check the type 
     if (cell.DataType != null && cell.DataType == CellValues.SharedString) 
     { 
      //it's a shared string so use the cell inner text as the index into the 
      //shared strings table 
      Console.WriteLine(sst.ChildElements[int.Parse(cell.InnerText)].InnerText); 
     } 
     else 
     { 
      //it's NOT a shared string, output the value directly 
      Console.WriteLine(cell.InnerText); 
     } 

     i = i + 1; 
    } 

} 

無論其...

上面的代碼將工作,但你正在嘗試做的方式索引細胞很容易出錯。 OpenXML架構允許從文件中省略空白單元格(和行)。這意味着如果你在某個地方有一個空單元格,你最終可能會得到錯誤的值。

例如,我創建的文件在Excel具有以下結構: Excel file with empty B2 cell

運行在該文件中的上述代碼產生輸出:

請注意,在第一行我們解析我們最終從I2得到的值,但在第二行,我們讀取我們得到的值從H3。我們讀取的第一行是1(假設第7個索引表示您希望列H),因爲該行的XML中沒有列B。這就是大部分讀取Excel文件的代碼使用循環遍歷單元格的原因。

0

的基本算法,通過行interate包括兩個循環:一個用於行其他的細胞。

假設你有一個工作表。

這是你如何讓行的集合。

IEnumerable<Row> rows = worksheet.Descendants<Row>(); 

在某行,甲肝細胞的集合。

所以,你需要對行的第一環

foreach (Row row in rows) 
{ 
} 

在這裏你可以得到細胞的集合行

IEnumerable<Cell> cells = row.Descendants<Cell>() 

然後你就可以在內部循環,通過細胞循環

foreach (Cell cell in cells) 
{ 
    //Here goes the logic of reading cell value 
} 
+0

謝謝,我試圖只引用給定的行列沒有循環單元格。由於在每一行我想通過它們的邏輯索引no,col 1,col 2等來引用這些字段 – John

相關問題