#サンプル
OpenXMLを使いExcelを読み込みタブ区切りでConsoleに出力するサンプルを作成した。
参考にしたページは下記の通り。
- Open XML SDK 2.0を使用してExcel 2010 ブック内のセルの値を取得する
- 「Open-XML-SDKを使ってExcelファイルの中をのぞいてみた」blog
- 「C#でExcel(xlsx)ファイルを読み込み、セルの値を取得する(OpenXML使用)」blog
環境は下記のとおり。
- Visual Studio 2013 Pro C#
- Open XML SDK 2.5 for Microsoft Office
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
namespace SampleOpenXML
{
class Program
{
static void Main(string[] args)
{
var fileName = @"C:\Users\LocalUser\Documents\sampleOpenXML.xlsx";
using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, false))
{
var wbPart = document.WorkbookPart;
var stringTable = wbPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
foreach (var sheet in wbPart.Workbook.Descendants<Sheet>())
{
if (sheet.Name == "Sheet1")
{
var wsheetPart = wbPart.GetPartById(sheet.Id) as WorksheetPart;
if (wsheetPart == null)
{
Console.WriteLine("WorksheetPart Not Found !!");
return;
}
var ws = wsheetPart.Worksheet;
foreach (var row in ws.Descendants<Row>())
{
var list = new List<string>();
foreach (Cell cell in row)
{
string value = cell.InnerText;
if (cell.DataType != null)
{
switch (cell.DataType.Value)
{
case CellValues.Boolean:
case CellValues.Date:
case CellValues.Error:
case CellValues.InlineString:
case CellValues.Number:
case CellValues.String:
value = cell.InnerText;
break;
case CellValues.SharedString:
if (stringTable != null)
value = stringTable.SharedStringTable.ElementAt(int.Parse(value)).InnerText;
break;
default:
break;
}
}
list.Add(value);
}
Console.WriteLine(string.Join("\t", list.ToArray()));
}
}
}
}
}
}
}
##その後
その後、実際のデータを取り込んだところ漢字文字列がカタカナ付きで取得された。例えば「内科」とExcelには表示されているが「内科ナイカ」と取得された。
SharedStringTable から取得するとき、下記のように変更した。
if (stringTable != null)
{
var element = stringTable.SharedStringTable.ElementAt(int.Parse(value));
value = element.FirstChaid.InnerText;
}
##その後のその後
その後のその後、数式のCellを取り込もうとすると、数式と値が同時に取得されたり、文字列が分かれて格納されていることがわかり下記のような関数を作成した。
private static string GetCellValue(Cell cell, SharedStringTable sTable)
{
string value = cell.InnerText;
// 式が入っている場合
if (cell.CellFormula != null)
return cell.CellValue.Text;
// データタイプ、SharedStringTableがnull、DataTypeがSharedString以外
if (cell.DataType == null || sTable == null)
return value;
if (cell.DataType.Value != CellValues.SharedString)
return value;
var element = sTable.ElementAt(int.Parse(value));
// 子Nodeがなければ、最初のNodeの値を返す
if (!element.HasChildren)
return element.FirstChild.InnerText;
// 子Nodeからデータを取得し結合して返す
var sb = new StringBuilder();
foreach (var node in element.ChildElements)
{
switch (node.LocalName)
{
case "t":
case "r":
sb.Append(node.InnerText);
break;
}
}
return sb.ToString();
}
読み込みは下記のように変更した。
foreach (Cell cell in row)
{
list.Add(GetCellValue(cell, stringTable));
}
#日付の取得
日付の取得は、DateTime.DateTimeOADateを使用してDateTimeに変換する。