2016-01-22 32 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

相关问题