Strict Open XML 形式のブックをコンポーネントで扱う

Open XML SDL 2.5 CTP 版と ExcelCreator を使用し、プログラム中から Strict Open XML 形式の Excel ブック (.xlsx) を扱う方法を紹介します。


◆検証環境
OS Windows 8(x64)
開発環境 Visual Studio 2012
CPU Intel(R) Core(TM)2 Duo E8400 @ 3.00GHz
メモリ 4GB
その他 SSD 搭載


◆Open XML SDK 2.5 を使用して Strict Open XML 形式を扱う

Open XML SDK 2.5 の CTP 版では、Strict Open XML 形式の読み込みがサポートされます。Visual Studio 2012 でコンソールアプリケーション「OXML25ConsoleApplication」を新規作成し、Open XML SDK 2.5 のアセンブリへの参照を追加してコードを述していきます。

ブックをオープンしてセルに値を設定するコード(Open XML SDK 2.5)

using System;
using System.Diagnostics;
using System.Linq;
using System.Drawing;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;

namespace OXML25ConsoleApplication
{
    /// <summary>
    /// Program クラス
    /// </summary>
    class Program
    {
        /// <summary>
        /// private メンバ
        /// </summary>
        private static SpreadsheetDocument spreadsheetDocument = null;
        private static WorkbookPart workbookPart = null;
        private static WorksheetPart worksheetPart = null;
        private static SharedStringTablePart sharedStringPart = null;
        /// <summary>
        /// Main
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            TimeSpan ts = new TimeSpan();
            sw.Start();
            Console.WriteLine("Open XML SDK 2.5 による Strict Open XML 形式のブックのオープン。");

            // SpreadsheetDocument をオープンします。
            spreadsheetDocument = SpreadsheetDocument.Open(@"明細s.xlsx", true);

            // WorkbookPart を取得します。
            workbookPart = spreadsheetDocument.WorkbookPart;

            // WorksheetPart を取得します。
            IEnumerable<Sheet> sheets = spreadsheetDocument.WorkbookPart.Workbook.Descendants<Sheet>().Where
                (s => s.Name == "Sheet1");
            worksheetPart = (WorksheetPart)spreadsheetDocument.WorkbookPart.GetPartById(sheets.First().Id);

            // SharedStringTablePart を作成します。
            OpensharedStringPart();

            // データの設定
            SetData();

            // ワークブックを保存します。
            workbookPart.Workbook.Save();

            // ドキュメントをクローズします。
            spreadsheetDocument.Close();

            ts = sw.Elapsed;
            Console.WriteLine("Open XML SDK 2.5 処理時間:{0}", ts.ToString());
            Process currentProcess = System.Diagnostics.Process.GetCurrentProcess();
            currentProcess.Refresh();
            Console.WriteLine("プロセス名   :" + currentProcess.ProcessName + "\n" +
                "物理メモリ使用量:" + (currentProcess.WorkingSet64 / 1024) + " KB\n" +
                "仮想メモリ使用量:" + (currentProcess.VirtualMemorySize64 / 1024) + " KB");

        }
        /// <summary>
        /// データを設定します。
        /// </summary>
        /// <param name="sheet"></param>
        private static void SetData()
        {
            // データ
            SetValue("B", 3, "ExcelCreator 2012");
            SetValue("C", 3, 1);
            SetValue("D", 3, 63000);
            SetValue("E", 3, 63000);
            SetValue("B", 4, "VB-Report 7");
            SetValue("C", 4, 1);
            SetValue("D", 4, 81900);
            SetValue("E", 4, 81900);
            SetValue("B", 5, "Open XML SDK 2.5 CTP 版によるデータの書き込み。(Strict Open XML 形式)");
        }
        /// <summary>
        /// SharedStringTable を開く
        /// </summary>
        private static void OpensharedStringPart()
        {
            if (spreadsheetDocument == null) return;
            if (spreadsheetDocument.WorkbookPart.GetPartsOfType<SharedStringTablePart>().Count() > 0)
                sharedStringPart = spreadsheetDocument.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First();
            else
                sharedStringPart = spreadsheetDocument.WorkbookPart.AddNewPart<SharedStringTablePart>();
        }
        /// <summary>
        /// SharedStringTable への値の設定
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        private static int InsertSharedStringItem(string text)
        {
            if (sharedStringPart == null) return -1;
            // 共有文字列テーブルのデータがない場合新規で作成する。
            if (sharedStringPart.SharedStringTable == null)
                sharedStringPart.SharedStringTable = new SharedStringTable();
            int index = 0;
            foreach (SharedStringItem item in sharedStringPart.SharedStringTable.Elements<SharedStringItem>())
            {
                if (item.InnerText == text)
                    return index;
                index++;
            }
            // 共有文字列に文字を設定
            sharedStringPart.SharedStringTable.AppendChild(new SharedStringItem(new DocumentFormat.OpenXml.Spreadsheet.Text(text)));
            return index;
        }
        /// <summary>
        /// 値の設定
        /// </summary>
        /// <param name="columnName"></param>
        /// <param name="rowIndex"></param>
        /// <param name="value"></param>
        private static void SetValue(string columnName, int rowIndex, object value)
        {
            Type type = value.GetType();

            string valueString = "";
            if (value != null)
                valueString = value.ToString();
            Cell cell = InsertCellInWorksheet(columnName, rowIndex, -1);
            if (type == typeof(string))
            {
                // Insert the result into the SharedStringTablePart.
                int index = InsertSharedStringItem(valueString);

                cell.CellValue = new CellValue(index.ToString());
                cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
            }
            else
            {
                cell.CellValue = new CellValue(valueString);
                cell.DataType = new EnumValue<CellValues>(CellValues.Number);
            }
            return;
        }
        /// <summary>
        /// セル情報の検索と取得(存在しない場合は新規追加)
        /// </summary>
        /// <param name="columnName"></param>
        /// <param name="rowIndex"></param>
        /// <param name="styleIndex"></param>
        /// <returns></returns>
        private static Cell InsertCellInWorksheet(string columnName, int rowIndex, int styleIndex)
        {
            if (worksheetPart == null) return null;
            Worksheet worksheet = worksheetPart.Worksheet;
            SheetData sheetData = worksheet.GetFirstChild<SheetData>();
            string cellReference = columnName + rowIndex.ToString();

            // 列情報があるかを確認し、無い場合は新規で作成する。
            Row row;
            if (sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0)
                row = sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).First();
            else
            {
                Row refRow = null;
                foreach (Row r in sheetData.Elements<Row>())
                {
                    if (r.RowIndex > rowIndex)
                    {
                        refRow = r;
                        break;
                    }
                }
                row = new Row() { RowIndex = (uint)rowIndex };
                sheetData.InsertBefore(row, refRow);
            }

            // 列番号から、セルの存在を確認する。
            if (row.Elements<Cell>().Where(c => c.CellReference.Value == columnName + rowIndex.ToString()).Count() > 0)
                return row.Elements<Cell>().Where(c => c.CellReference.Value == cellReference).First();
            else
            {
                Cell refCell = null;
                foreach (Cell cell in row.Elements<Cell>())
                {
                    if (string.Compare(cell.CellReference, cellReference) > 0)
                    {
                        refCell = cell;
                        break;
                    }
                }
                Cell newCell = new Cell() { CellReference = cellReference };
                if (styleIndex >= 0) newCell.StyleIndex = new UInt32Value((uint)styleIndex);
                row.InsertBefore(newCell, refCell);
                return newCell;
            }
        }
    }
}

Open XML SDK 2.5 の CTP 版の詳細は下記のサイトで紹介されています。

Open XML SDK 2.5 CTP for Office の新機能

Open XML SDK 2.5 の CTP 版では、読み込みはサポートされていますが、ブックを保存する場合は従来の Open XML 移行型 (Transitional) 形式のブックとして保存されます。そのため、新規に Strict Open XML 形式でブックを作成することはできないようです。実際に作成されたファイルの内容を見てみると、タグは Strict 形式のもので出力されていますが、各パーツの「xmlns」が従来のネームスペースのままで作成されています。

xl/workbook.xml の内容

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<x:workbook 
  xmlns:x15ac="http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac" 
  xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" 
  xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" 
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main" 
  conformance="strict" 
  mc:Ignorable="x15" 
  xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<x:fileVersion appName="xl" lastEdited="6" lowestEdited="6" rupBuild="14420" />
<x:workbookPr dateCompatibility="0" defaultThemeVersion="153222" />
<mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<mc:Choice Requires="x15">
<x15ac:absPath xmlns:x15ac="http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac" url="D:\OpenBook\Release\" />
</mc:Choice>
</mc:AlternateContent>
<x:bookViews>
<x:workbookView xWindow="0" yWindow="0" windowWidth="14880" windowHeight="8055" />
</x:bookViews>
<x:sheets>
<x:sheet name="Sheet1" sheetId="1" r:id="rId1" />
</x:sheets>
<x:calcPr calcId="152511" />
<x:extLst>
<x:ext xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" uri="{79F54976-1DA5-4618-B147-4CDE4B953A38}">
<x14:workbookPr />
</x:ext>
<x:ext xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main" uri="{140A7094-0E35-4892-8432-C4D2E57EDEB5}">
<x15:workbookPr chartTrackingRefBase="1" />
</x:ext>
</x:extLst>
</x:workbook>

尚、Open XML SDK 2.5 で作成したブックを Excel 2013 で開き、名前を付けて保存を選択すると、ファイルの種類にはデフォルトで「Strict Open XML スプレッドシート (*xlsx)」が選択されます。



◆ExcelCreator を使用して Strict Open XML 形式を扱う

ExcelCreator 8.0 for .NET では、2013/2/7 公開のアップデート版 (Ver8.0.5270.1707) から Strict Open XML 形式のブックがサポートされます。Visual Studio 2012 でコンソールアプリケーション「EC8ConsoleApplication」を新規作成し、ExcelCreator の各アセンブリへの参照および System.Drawing への参照を追加してコードを述していきます。

Strict Open XML 形式のブックを新規に作成するコード(ExcelCreator 8.0 for .NET)

using System;
using System.Diagnostics;
using AdvanceSoftware.ExcelCreator;
using AdvanceSoftware.ExcelCreator.Xlsx;
using System.Drawing;

namespace EC8ConsoleApplication
{
    /// <summary>
    /// Program クラス
    /// </summary>
    class Program
    {
        /// <summary>
        /// Main
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            TimeSpan ts = new TimeSpan();
            sw.Start();
            Console.WriteLine("ExcelCreator 8.0 for .NET による Strict Open XML 形式の新規作成。");

            var xlsxCreator = new XlsxCreator();
            // ブックの新規作成 - Strict Open XML 形式
            xlsxCreator.CreateBook("EC8Create.xlsx", 1, xlsxVersion.ver2013S);
            // シート名の設定
            xlsxCreator.SheetName = "明細";
            // レイアウトの設定
            SetLayout(xlsxCreator);
            // データの設定
            SetData(xlsxCreator);
            // ブックのクローズ
            xlsxCreator.CloseBook(true);

            ts = sw.Elapsed;
            Console.WriteLine("ExcelCreator 8.0 for .NET 処理時間:{0}", ts.ToString());
            Process currentProcess = System.Diagnostics.Process.GetCurrentProcess();
            currentProcess.Refresh();
            Console.WriteLine("プロセス名   :" + currentProcess.ProcessName + "\n" +
                "物理メモリ使用量:" + (currentProcess.WorkingSet64 / 1024) + " KB\n" +
                "仮想メモリ使用量:" + (currentProcess.VirtualMemorySize64 / 1024) + " KB");

        }
        /// <summary>
        /// レイアウトを設定します。
        /// </summary>
        /// <param name="xlsxCreator"></param>
        private static void SetLayout(XlsxCreator xlsxCreator)
        {
            if (xlsxCreator == null) return;
            // 罫線
            xlsxCreator.Cell("B2:E4").Attr.Box(BoxType.Ltc, BorderStyle.Medium, xlColor.Blue);
            // 背景色
            xlsxCreator.Cell("B2:E2").Attr.BackColor = Color.Blue;
            // タイトル行
            xlsxCreator.Cell("B2:E2").Attr.FontColor = Color.White;
            xlsxCreator.Cell("B2").Value = "商品名";
            xlsxCreator.Cell("C2").Value = "数量";
            xlsxCreator.Cell("D2").Value = "単価";
            xlsxCreator.Cell("E2").Value = "金額";
        }
        /// <summary>
        /// データを設定します。
        /// </summary>
        /// <param name="xlsxCreator"></param>
        private static void SetData(XlsxCreator xlsxCreator)
        {
            if (xlsxCreator == null) return;
            // データ
            xlsxCreator.Cell("B3").Value = "ExcelCreator 2012";
            xlsxCreator.Cell("C3").Value = 1;
            xlsxCreator.Cell("D3").Value = 63000;
            xlsxCreator.Cell("E3").Value = 63000;
            xlsxCreator.Cell("B4").Value = "VB-Report 7";
            xlsxCreator.Cell("C4").Value = 1;
            xlsxCreator.Cell("D4").Value = 81900;
            xlsxCreator.Cell("E4").Value = 81900;
        }
    }
}

ExcelCreator を使用して Strict Open XML 形式のブックを新規に作成するには、CreateBook メソッドのバージョンを指定する引数に「ver2013S」を指定します。作成されたブックの拡張子を「.zip」に変更して内容を確認すると Strict Open XML 形式で作成されていることが分かります。尚、バージョン指定時に「ver2013」を指定すると、Excel 2013 の従来の Open XML 移行型 (Transitional) 形式で作成されます。

xl/workbook.xml の内容

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<workbook 
  xmlns="http://purl.oclc.org/ooxml/spreadsheetml/main" 
  xmlns:r="http://purl.oclc.org/ooxml/officeDocument/relationships" 
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  mc:Ignorable="x15" 
  xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main" 
  conformance="strict">
<fileVersion appName="xl" lastEdited="6" lowestEdited="6" rupBuild="14420" />
<workbookPr dateCompatibility="0" defaultThemeVersion="153222" />
<mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<mc:Choice Requires="x15">
<x15ac:absPath url="D:\OpenBook\" xmlns:x15ac="http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac" />
</mc:Choice>
</mc:AlternateContent>
<bookViews>
<workbookView xWindow="0" yWindow="0" windowWidth="15780" windowHeight="7710" />
</bookViews>
<sheets>
<sheet name="明細" sheetId="1" r:id="rId3" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" />
</sheets>
<calcPr calcId="152511" />
<extLst>
<ext uri="{79F54976-1DA5-4618-B147-4CDE4B953A38}" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main">
<x14:workbookPr />
</ext>
<ext uri="{140A7094-0E35-4892-8432-C4D2E57EDEB5}" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main">
<x15:workbookPr chartTrackingRefBase="1" />
</ext>
</extLst>
</workbook>


次に既存の Strict Open XML 形式のブックをオープンしてセルにデータを書き込み別のファイルとして保存を行います。

ブックをオープンしてセルに値を設定するコード(ExcelCreator 8.0 for .NET)

using System;
using System.Diagnostics;
using AdvanceSoftware.ExcelCreator;
using AdvanceSoftware.ExcelCreator.Xlsx;
using System.Drawing;

namespace EC8ConsoleApplication
{
    /// <summary>
    /// Program クラス
    /// </summary>
    class Program
    {
        /// <summary>
        /// Main
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            TimeSpan ts = new TimeSpan();
            sw.Start();
            Console.WriteLine("ExcelCreator 8.0 for .NET による Strict Open XML 形式のブックのオープン。");

            var xlsxCreator = new XlsxCreator();
            // ブックのオープン
            xlsxCreator.OpenBook("EC8Open.xlsx", "明細s.xlsx");
            // データの設定
            SetData(xlsxCreator);
            // ブックのクローズ
            xlsxCreator.CloseBook(true);

            ts = sw.Elapsed;
            Console.WriteLine("ExcelCreator 8.0 for .NET 処理時間:{0}", ts.ToString());
            Process currentProcess = System.Diagnostics.Process.GetCurrentProcess();
            currentProcess.Refresh();
            Console.WriteLine("プロセス名   :" + currentProcess.ProcessName + "\n" +
                "物理メモリ使用量:" + (currentProcess.WorkingSet64 / 1024) + " KB\n" +
                "仮想メモリ使用量:" + (currentProcess.VirtualMemorySize64 / 1024) + " KB");
        }
        /// <summary>
        /// データを設定します。
        /// </summary>
        /// <param name="xlsxCreator"></param>
        private static void SetData(XlsxCreator xlsxCreator)
        {
            if (xlsxCreator == null) return;
            // データ
            xlsxCreator.Cell("B3").Value = "ExcelCreator 2012";
            xlsxCreator.Cell("C3").Value = 1;
            xlsxCreator.Cell("D3").Value = 63000;
            xlsxCreator.Cell("E3").Value = 63000;
            xlsxCreator.Cell("B4").Value = "VB-Report 7";
            xlsxCreator.Cell("C4").Value = 1;
            xlsxCreator.Cell("D4").Value = 81900;
            xlsxCreator.Cell("E4").Value = 81900;
            xlsxCreator.Cell("B5").Value = "ExcelCreator 8.0 for .NET によるデータの書き込み。(Strict Open XML 形式)";
        }
    }
}

既存のブックをオープンするには OpenBook メソッドを使用します。この場合、元のファイルの形式をそのまま引き継ぎます。



◆まとめ

Strict Open XML 形式と従来の Open XML 移行型 (Transitional) 形式は、現状ではわずかな違いですが、他のアプリケーションの互換等で使用されるケースが出てくる可能性はあると思いますので、引き続き動向を見ていきたいと思います。

You can leave a response, or trackback from your own site.

Leave a Reply