6

OpenXML API を使用してセル データを取得する方法について、Web でたくさんの情報を読みました。しかし、特に簡単なものはあまりありません。ほとんどは、読み取りではなく、SpreadsheetML への書き込みに関するものであるように思われますが、それでもあまり役に立ちません。テーブルを含むスプレッドシートがあります。テーブル名が何であるかを知っており、それがどのシートにあり、どの列がテーブルにあるかを知ることができます。しかし、テーブル内のデータを含む行のコレクションを取得する方法がわかりません。

ドキュメントをロードしてワークブックへのハンドルを取得するには、次のようにします。

SpreadsheetDocument document = SpreadsheetDocument.Open("file.xlsx", false);
WorkbookPart workbook = document.WorkbookPart;

テーブル/シートを見つけるためにこれを持っています:

Table table = null;
foreach (Sheet sheet in workbook.Workbook.GetFirstChild<Sheets>())
{
    WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheet.Id);
    foreach (TableDefinitionPart tableDefinitionPart in worksheetPart.TableDefinitionParts)
    {
        if (tableDefinitionPart.Table.DisplayName == this._tableName)
        {
            table = tableDefinitionPart.Table;
            break;
        }
    }
}

また、table.TableColumns を foreaching することで、テーブル内の列を反復処理できます。

4

2 に答える 2

4

OpenXML API を使用して Excel 2007/2010 スプレッドシートを読み取るのは非常に簡単です。私たちが常に迅速で汚いソリューションとして行ってきたように、OleDBを使用するよりもなんとなく簡単です。さらに、単純なだけでなく冗長です。ここにすべてのコードを配置しても、コメントや説明が必要な場合は役に立たないと思うので、要約だけを書いて、良い記事にリンクします. MSDN のこの記事を読んでください。XLSX ドキュメントを非常に簡単に読む方法が説明されています。

要約すると、次のようになります。

  • SpreadsheetDocumentで開きSpreadsheetDocument.Openます。
  • Sheetドキュメントのから LINQ クエリを使用して、必要なものを取得しますWorkbookPart
  • の Id を使用して(最終的に!) WorksheetPart(必要なオブジェクト) を取得しますSheet

コードでは、コメントとエラー処理を取り除きます:

using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, false))
{
   Sheet sheet = document.WorkbookPart.Workbook
      .Descendants<Sheet>()
      .Where(s => s.Name == sheetName)
      .FirstOrDefault();

   WorksheetPart sheetPart = 
      (WorksheetPart)(document.WorkbookPart.GetPartById(theSheet.Id));
}

今(しかし、使用中!)あなたがしなければならないことは、セル値を読むことです:

Cell cell = sheetPart.Worksheet.Descendants<Cell>().
    Where(c => c.CellReference == addressName).FirstOrDefault();

行を列挙する必要がある場合 (そして行がたくさんある場合)、最初にSheetDataオブジェクトへの参照を取得する必要があります。

SheetData sheetData = sheetPart.Worksheet.Elements<SheetData>().First();

これで、すべての行とセルを求めることができます:

foreach (Row row in sheetData.Elements<Row>())
{
   foreach (Cell cell in row.Elements<Cell>())
   {
      string text = cell.CellValue.Text;
      // Do something with the cell value
   }
}

通常のスプレッドシートを単純に列挙するDescendants<Row>()には、WorksheetPartオブジェクトを使用できます。

OpenXML に関するリソースがさらに必要な場合は、OpenXML Developerを参照してください。これには、優れたチュートリアルが多数含まれています。

于 2012-03-20T23:04:07.843 に答える
1

これをコーディングするにはもっと良い方法がたくさんあると思いますが、私はそれが必要だったのでまとめました。

using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Packaging;

    private static DataTable genericExcelTable(FileInfo fileName)
    {
        DataTable dataTable = new DataTable();
        try
        {
            using (SpreadsheetDocument doc = SpreadsheetDocument.Open(fileName.FullName, false))
            {
                Workbook wkb = doc.WorkbookPart.Workbook;
                Sheet wks = wkb.Descendants<Sheet>().FirstOrDefault();
                SharedStringTable sst = wkb.WorkbookPart.SharedStringTablePart.SharedStringTable;
                List<SharedStringItem> allSSI = sst.Descendants<SharedStringItem>().ToList<SharedStringItem>();
                WorksheetPart wksp = (WorksheetPart)doc.WorkbookPart.GetPartById(wks.Id);

                foreach (TableDefinitionPart tdp in wksp.TableDefinitionParts)
                {
                    QueryTablePart qtp = tdp.QueryTableParts.FirstOrDefault<QueryTablePart>();
                    Table excelTable = tdp.Table;
                    int colcounter = 0;
                    foreach (TableColumn col in excelTable.TableColumns)
                    {
                        DataColumn dcol = dataTable.Columns.Add(col.Name);
                        dcol.SetOrdinal(colcounter);
                        colcounter++;
                    }

                    SheetData data = wksp.Worksheet.Elements<SheetData>().First();

                    foreach (DocumentFormat.OpenXml.Spreadsheet.Row row in data)
                    {
                        if (isInTable(row.Descendants<Cell>().FirstOrDefault(), excelTable.Reference, true))
                        {
                            int cellcount = 0;
                            DataRow dataRow = dataTable.NewRow();
                            foreach (Cell cell in row.Elements<Cell>())
                            {

                                if (cell.DataType != null && cell.DataType.InnerText == "s")
                                {
                                    dataRow[cellcount] = allSSI[int.Parse(cell.CellValue.InnerText)].InnerText;
                                }
                                else
                                {
                                    dataRow[cellcount] = cell.CellValue.Text;
                                }
                                cellcount++;
                            }
                            dataTable.Rows.Add(dataRow);
                        }
                    }
                }
            }
            //do whatever you want with the DataTable
            return dataTable;
        }
        catch (Exception ex)
        {
            //handle an error
            return dataTable;
        }
    }
    private static Tuple<int, int> returnCellReference(string cellRef)
    {
        int startIndex = cellRef.IndexOfAny("0123456789".ToCharArray());
        string column = cellRef.Substring(0, startIndex);
        int row = Int32.Parse(cellRef.Substring(startIndex));
        return new Tuple<int,int>(TextToNumber(column), row);
    }
    private static int TextToNumber(string text)
    {
        return text
            .Select(c => c - 'A' + 1)
            .Aggregate((sum, next) => sum * 26 + next);
    }
    private static bool isInTable(Cell testCell, string tableRef, bool headerRow){
        Tuple<int, int> cellRef = returnCellReference(testCell.CellReference.ToString());
        if (tableRef.Contains(":"))
        {
            int header = 0;
            if (headerRow)
            {
                header = 1;
            }
            string[] tableExtremes = tableRef.Split(':');
            Tuple<int, int> startCell = returnCellReference(tableExtremes[0]);
            Tuple<int, int> endCell = returnCellReference(tableExtremes[1]);
            if (cellRef.Item1 >= startCell.Item1
                && cellRef.Item1 <= endCell.Item1
                && cellRef.Item2 >= startCell.Item2 + header
                && cellRef.Item2 <= endCell.Item2) { return true; }
            else { return false; }
        }
        else if (cellRef.Equals(returnCellReference(tableRef)))
        {
            return true;
        } 
        else 
        {
            return false;
        }
    }
于 2014-03-12T22:30:58.320 に答える