2011-09-21 11 views
9

Ho un documento di calcolo che contiene 182 colonne. Ho bisogno di inserire i dati del foglio di calcolo in una tabella dati, scheda per scheda, ma ho bisogno di scoprire come sto aggiungendo i dati da ciascuna scheda, qual è il nome della scheda e aggiungere il nome della scheda a una colonna nella tabella dei dati .Come recuperare i nomi delle schede dal foglio Excel utilizzando OpenXML

Ecco come ho impostato la tabella dati.

I loop quindi nella cartella di lavoro e drill-down per l'oggetto sheetData e camminare attraverso ogni riga e colonna, ottenendo i dati della cella.

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))); 

Tuttavia, alla fine della matrice di stringhe che uso per la Tabella dati, ho bisogno di aggiungere il nome della scheda. Come posso trovare il nome della scheda mentre eseguo il looping nel foglio in Open XML?

Ecco il mio codice finora:

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; 

Solo una nota: in precedenza ho ricevuto i nomi delle schede dalla proprietà InnerXml di "lista" in

OpenXmlElementList list = sheets.ChildElements; 

però ho notato come ho 'm looping nel foglio di calcolo non ottiene i nomi delle schede nel giusto ordine.

+0

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

+0

che funziona bene se voglio solo estrarre i nomi delle schede ... che posso, analizzando l'interno/esterno xml .. ma voglio farlo nel mio ciclo For .. Sto avendo problemi ad accedere a Sheet mentre io sono all'interno del livello SheetData. – Kwalke001

+0

Non puoi lavorare con l'oggetto "foglio di lavoro" per ottenere il suo nome? L'ultimo esempio di codice in quella pagina mostra come eseguire il loop degli attributi di un foglio: presumibilmente il nome del foglio è uno di quegli attributi (non ho esperienza però). –

risposta

15

I nomi dei fogli vengono memorizzati nella WorkbookPart in un elemento Sheets che ha figli di elemento Sheet che corrisponde ad ogni foglio di lavoro nel file Excel. Tutto quello che devi fare è prendere l'indice corretto da quell'elemento Sheets e quello sarà il Sheet nel tuo ciclo. Ho aggiunto uno snippet di codice qui sotto per fare ciò che vuoi.

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

questa era una soluzione eccellente. Grazie, amurra! – Kwalke001

+3

Dalla mia esperienza, utilizzando il proprio frammento di codice, sheetName legge i nomi dei fogli nell'ordine corretto (così come sono nel file), ma sheetData non viene letto nello stesso ordine in cui si trovano nel file di Excel. Di conseguenza, il codice genera nomi misti per tutti i fogli. – Skull

+2

Sembra che il problema derivi dal file "excel_file.xlsx \ xl \ _rels \ workbook.xml.rels", che ha nomi di fogli di calcolo e riferimenti al contenuto del foglio di calcolo archiviato in un ordine casuale. Se si riordinano manualmente da 1 a N (Id = "rId1", Id = "rId2", ..., Id = "rIdN"), i nomi dei fogli di calcolo si allineeranno con il loro contenuto dopo aver letto il file. Non ho idea di come gestire questo problema nel codice però. – 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

Sarebbe bello se potessi aggiungere qualche discussione sul perché il tuo metodo funziona in aggiunta al codice. – ASGM

+0

In questo modo ha più senso per me mentre cerco il foglio tramite il nome, ottenendo l'id di quel foglio e quindi ottenendo il foglio di lavoro in base al nome (usando linq significa che non è necessario eseguire il ciclo) . La risposta contrassegnata come risposta utilizza un indice che richiede il passaggio in cascata finché non hai trovato ciò che desideri. – wavydavy

21

Ecco un metodo di supporto a portata di mano per ottenere il foglio corrispondente ad un WorksheetPart:

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); 
} 

allora si può ottenere il nome dai fogli Nome-proprietà:

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

... questo sarà l'OP "nome della scheda" a cui si fa riferimento.


Per la cronaca il metodo opposto sarà simile:

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

... e con questo possiamo anche aggiungere il seguente metodo:

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))); 
} 

Ora si può facilmente enumerare attraverso tutti i fogli di lavoro incluso il loro nome.

buttare tutto in un dizionario per il nome a base di ricerca Se si preferisce che:

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

...o se volete semplicemente un foglio specifico per nome:

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

(Quindi chiamare GetWorkSheetFromSheet per ottenere il relativo foglio di lavoro.)

+2

Questa dovrebbe essere la soluzione corretta. –

+0

Brilliant .. Grazie !! – Jason