2011-09-21 73 views
9

我有一個電子表格文檔,其中有182列。我需要將電子表格數據放入一個數據表中,但是我需要找出每個標籤添加數據,標籤名稱是什麼,並將標籤名稱添加到數據表中的一列。如何使用OpenXML從Excel表格中檢索標籤名稱

這是我如何設置數據表。

然後,我在工作簿中循環並深入到sheetData對象並遍歷每行和每列,獲取單元格數據。

DataTable dt = new DataTable(); 
for (int i = 0; i <= col.GetUpperBound(0); i++) 
{ 
    try 
    { 
     dt.Columns.Add(new DataColumn(col[i].ToString(), typeof(string))); 
    } 
    catch (Exception e) 
    { 
     MessageBox.Show("Uploader Error" + e.ToString()); 
     return null; 
    } 
} 

dt.Columns.Add(new DataColumn("SheetName", typeof(string))); 

但是,在我用於數據表的字符串數組的末尾,我需要添加標籤名稱。我如何在Open XML的工作表中循環查找標籤名稱?

這是到目前爲止我的代碼:

using (SpreadsheetDocument spreadSheetDocument = 
      SpreadsheetDocument.Open(Destination, false)) 
{ 
    WorkbookPart workbookPart = spreadSheetDocument.WorkbookPart; 
    Workbook workbook = spreadSheetDocument.WorkbookPart.Workbook; 

    Sheets sheets = 
     spreadSheetDocument 
      .WorkbookPart 
      .Workbook 
      .GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.Sheets>(); 

    OpenXmlElementList list = sheets.ChildElements; 

    foreach (WorksheetPart worksheetpart in workbook.WorkbookPart.WorksheetParts) 
    { 
     Worksheet worksheet = worksheetpart.Worksheet; 

     foreach (SheetData sheetData in worksheet.Elements<SheetData>()) 
     { 
      foreach (Row row in sheetData.Elements()) 
      { 
       string[] thisarr = new string[183]; 
       int index = 0; 
       foreach (Cell cell in row.Elements()) 
       { 
        thisarr[(index)] = GetCellValue(spreadSheetDocument, cell); 
        index++; 
       } 
       thisarr[182] = ""; //need to add tabname here 
       if (thisarr[0].ToString() != "") 
       { 
        dt.Rows.Add(thisarr); 
       } 
      } 
     } 
    } 
} 

return dt; 

剛一說明:我在

OpenXmlElementList list = sheets.ChildElements; 

但是我注意到,我沒有以前得到「名單」的InnerXML屬性選項卡名稱在電子表格中循環時,它不會以正確的順序獲得標籤名稱。

+0

http://msdn.microsoft.com/en-us/library/bb507946。 aspx –

+0

工作正常,如果我只是想拉出標籤名稱..我可以通過解析出內部/外部xml ..但我想在我自己的For循環..我無法訪問表而im在SheetData級別.. – Kwalke001

+0

您無法使用「工作表」對象獲取其名稱?該頁面上的最後一個代碼示例顯示瞭如何循環顯示錶單的屬性:大概表單名稱是這些屬性之一(儘管我自己沒有經驗)。 –

回答

15

的片材的名稱被存儲在WorkbookPart在具有元件Sheet,其對應於在Excel文件每個工作表的兒童Sheets元件。您所要做的就是從Sheets元素中獲取正確的索引,這將是您循環中的Sheet。我在下面添加了一段代碼來做你想做的事情。

int sheetIndex = 0; 
foreach (WorksheetPart worksheetpart in workbook.WorkbookPart.WorksheetParts) 
{      
    Worksheet worksheet = worksheetpart.Worksheet; 

    // Grab the sheet name each time through your loop 
    string sheetName = workbookPart.Workbook.Descendants<Sheet>().ElementAt(sheetIndex).Name; 

    foreach (SheetData sheetData in worksheet.Elements<SheetData>()) 
    { 

     ... 
    } 
    sheetIndex++; 
} 
+0

這是一個很好的解決方案。謝謝阿穆拉! – Kwalke001

+3

根據我的經驗,使用您的代碼片段,sheetName以正確的順序(如它們在文件中)讀取表名,但sheetData不按照它們在Excel文件中的順序讀取。結果代碼導致所有工作表的混合名稱。 – Skull

+2

似乎問題來自「excel_file.xlsx \ xl \ _rels \ workbook.xml.rels」文件,該文件具有電子表格名稱和對以某種隨機順序存儲的電子表格內容的引用。如果您手動將它們從1重新排序到N(Id =「rId1」,Id =「rId2」,...,Id =「rIdN」),電子表格名稱將在讀取文件後與其內容對齊。不知道如何在代碼中處理這個問題。 – Skull

0
worksheet.GetAttribute("name","").Value 
4
Using spreadsheetDocument As SpreadsheetDocument = spreadsheetDocument.Open("D:\Libro1.xlsx", True) 

     Dim workbookPart As WorkbookPart = spreadsheetDocument.WorkbookPart 

     workbookPart.Workbook.Descendants(Of Sheet)() 



     Dim worksheetPart As WorksheetPart = workbookPart.WorksheetParts.Last 
     Dim text As String 



     For Each Sheet As Sheet In spreadsheetDocument.WorkbookPart.Workbook.Sheets 
      Dim sName As String = Sheet.Name 
      Dim sID As String = Sheet.Id 

      Dim part As WorksheetPart = workbookPart.GetPartById(sID) 
      Dim actualSheet As Worksheet = part.Worksheet 

      Dim sheetData As SheetData = part.Worksheet.Elements(Of SheetData)().First 

      For Each r As Row In sheetData.Elements(Of Row)() 
       For Each c As Cell In r.Elements(Of Cell)() 
        text = c.CellValue.Text 
        Console.Write(text & " ") 
       Next 
      Next 
     Next 

    End Using 

    Console.Read() 
+2

如果您可以添加一些關於代碼之外的原因的討論,那將會很棒。 – ASGM

+0

這種方式對我來說更有意義,因爲您通過名稱搜索工作表,獲取工作表的ID,然後根據名稱獲取工作表(使用linq意味着您根本不需要循環) 。標記爲答案的答覆使用需要循環播放的索引,直到找到所需內容爲止。 – wavydavy

21

這裏是一個方便的輔助方法來獲得對應於WorksheetPart圖紙:

Sheet sheet = GetSheetFromWorkSheet(myWorkbookPart, myWorksheetPart); 
string sheetName = sheet.Name; 

public static Sheet GetSheetFromWorkSheet 
    (WorkbookPart workbookPart, WorksheetPart worksheetPart) 
{ 
    string relationshipId = workbookPart.GetIdOfPart(worksheetPart); 
    IEnumerable<Sheet> sheets = workbookPart.Workbook.Sheets.Elements<Sheet>(); 
    return sheets.FirstOrDefault(s => s.Id.HasValue && s.Id.Value == relationshipId); 
} 

然後你可以從表名稱屬性獲取名稱

...這將成爲所提及的「標籤名稱」OP。


備案相反的方法看起來像:

public static Worksheet GetWorkSheetFromSheet(WorkbookPart workbookPart, Sheet sheet) 
{ 
    var worksheetPart = (WorksheetPart)workbookPart.GetPartById(sheet.Id); 
    return worksheetPart.Worksheet; 
} 

...與我們還可以添加下面的方法:

public static IEnumerable<KeyValuePair<string, Worksheet>> GetNamedWorksheets 
    (WorkbookPart workbookPart) 
{ 
    return workbookPart.Workbook.Sheets.Elements<Sheet>() 
     .Select(sheet => new KeyValuePair<string, Worksheet> 
      (sheet.Name, GetWorkSheetFromSheet(workbookPart, sheet))); 
} 

現在你可以很容易地枚舉通過所有工作表,包括他們的名字。

把它全部轉換成字典基於域名的查詢,如果你喜歡的是:

IDictionary<string, WorkSheet> wsDict = GetNamedWorksheets(myWorkbookPart) 
    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); 

...或者如果你只是想通過名字一個特定表:

public static Sheet GetSheetFromName(WorkbookPart workbookPart, string sheetName) 
{ 
    return workbookPart.Workbook.Sheets.Elements<Sheet>() 
     .FirstOrDefault(s => s.Name.HasValue && s.Name.Value == sheetName); 
} 

(然後調用GetWorkSheetFromSheet得到相應的工作表。)

+2

這應該是正確的解決方案。 –

+0

輝煌..謝謝! – Jason

相關問題