読者です 読者をやめる 読者になる 読者になる

とある技術の開発日記

Diary of irregular phrase programmer

Open-XML-SDK を使ってExcelファイルの中を覗いてみた

Microsoft C# Excel Office

先日、Open-XML-SDKがGitHub公開されました。

今までOpen-XMLには触れた事がなかったのですが、仕事でもExcelドキュメントを扱う機会が 圧倒的に増えそうなのでこの機会に触ってみることにしました。

GitHub:Open-XML-SDK

ビルド等の方法はGitHubのREADME.mdを参照すれば問題ないと思います。

ビルド手順(WindowsでVisualStudio 2013をインストール済みを想定)


  1. git cloneでリポジトリをコピー
  2. スタート > 「Visual Studio ツール」 > 「開発者コマンド プロンプト for VS2013」を管理者として実行
  3. powershellコマンドでpowershellモードへ
  4. 「Set-ExecutionPolicy Unrestricted」でPowerShell実行ポリシーを変更
  5. 1.で作成したリポジトリにある「BldSdk.ps1」を実行
  6. 5分程でバイナリファイルがbuild内に作成されます。

作成されたDLLを参照に追加すればOpen-XMLドキュメントをゴニョゴニョできます。

使ってみた


とりあえず、Excelファイルからセルの値を参照するプログラムはこんな感じ

static void Main(string[] args)
        {
            var fileName = (args.Length > 0) ? args[0] : string.Empty;
            var sheetName =(args.Length > 1) ? args[1] : string.Empty;

#if DEBUG
            fileName = @"C:\openxml-sample.xlsx";
            sheetName = "シート一番目";
#endif
            using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(fileName, true))
            {
                var workbookPart = spreadSheet.WorkbookPart;
                if (workbookPart == null)
                {
                    Console.WriteLine("WorkbookPart Not Found !!");
                    return;
                }

                var sheet = workbookPart.Workbook.Descendants<Sheet>().FirstOrDefault(s => s.Name == sheetName);
                if (sheet == null)
                {
                    Console.WriteLine("Sheet Not Found !!");
                    return;
                }

                var wsheetPart = workbookPart.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>())
                {
                    foreach (Cell cell in row)
                    {
                        string value = string.Empty;
                        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:
                                var stringTable = workbookPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
                                if (stringTable != null)
                                {
                                    value = stringTable.SharedStringTable.ElementAt(int.Parse(cell.InnerText)).InnerText;
                                }
                                break;
                            default:
                                break;
                        }
                        Console.WriteLine(string.Format("Adress {0}, Value {1}", cell.CellReference.Value, value));
                    }
                }
            }

            Console.WriteLine("終了するには何かキーを入力してください。");
            Console.ReadKey();
        }
    }

読み込むExcelはこのような物を読み込ませます。

f:id:airish9:20140709004038j:plain

この状態で実行すると以下のような結果になります。

Adress A1, Value 1行目1列目ギョウメレツメ
Adress B1, Value 1行目2列目ギョウメレツメ
Adress A2, Value 2行目1列目ギョウメレツメ
終了するには何かキーを入力してください。

結果で出ている通り"読み"もXMLデータに含まれているようです。

入力したデータだけ取り出すには先頭子要素のInnerTextを参照すると取り出すことができそうです。

stringTable.SharedStringTable.ElementAt(int.Parse(cell.InnerText)).FirstChild.InnerText;

この辺りはOpen-XMLのドキュメント仕様になるのですが、以下のサイトを参考にすると理解しやすかったです。

XMLを取り込んだ最新Officeフォーマットとは(前編):Officeファイルの成り立ちと最新形、そして標準化 (1/2) - @IT

Open XMLファイルの中身を見てみる « 空談録

感想


できることは多いのかもしれないですが、XML構造をしっかり理解していないといにくい印象を受けました。
もう少しVBAっぽくアクセスできたら良いと思うのですが、そこまでするには多くの作りこみが必要でしょう。

なお、Open XMLをラップするClosedXMLなるプロジェクトがあるようです。
こちらの方がスマートに書けるそうです。

ClosedXML
https://closedxml.codeplex.com/