Help us understand the problem. What is going on with this article?

C#でOpenXMLを使ったExcelの読み込み

More than 3 years have passed since last update.

サンプル

OpenXMLを使いExcelを読み込みタブ区切りでConsoleに出力するサンプルを作成した。
参考にしたページは下記の通り。

環境は下記のとおり。

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に変換する。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away