DioDocs for Excel
DioDocs for Excel
データソースの連結
帳票の作成 > データソースの連結

MS Excel を使用して、データフィールド、式フィールド、シート名フィールドなどを含む帳票テンプレートを作成したら、これらのテンプレートフィールドにデータソースを連結する必要があります。AddDataSource メソッドを使用してデータソースを追加し、ProcessTemplate メソッドを使用してテンプレートフィールドにデータを連結します。これにより、データソースからテンプレートフィールドにデータが入力され、Excel 帳票が作成されます。

なお、ProcessTemplate メソッドを使用した場合、Excel 帳票を作成する際に帳票テンプレートのワークブックは上書きされ、同じワークブックに帳票が作成されます。帳票テンプレートのワークブックを保持したまま Excel 帳票を作成するには、本トピックの最後にある「帳票テンプレートを保持したままの Excel 帳票作成」を参照してください。

また、連結するデータソースには、複数のデータソースやデータテーブルも使用できます。この場合、テンプレート構文では、データソースのオブジェクトに続いてデータフィールドを指定する必要があります。例えば、以下の帳票テンプレートでは、各クラスの情報を異なるデータソースから連結するように設定しています。

テンプレート構文は、以下のデータソースに対応しています。

DataTable

DataTable とは、任意の種類のデータベースの行と列のコレクションを持つ単一テーブルです。

 

テンプレート構文:[データソースの別名].[列名]

例:

{{ds.ID}}

{{ds.Name}}

 

DataTable のデータソースを連結

C#
コードのコピー
var datasource = new System.Data.DataTable();
datasource.Columns.Add(new DataColumn("ID", typeof(Int32)));
datasource.Columns.Add(new DataColumn("Name", typeof(string)));
datasource.Columns.Add(new DataColumn("Score", typeof(Int32)));
datasource.Columns.Add(new DataColumn("Team", typeof(string)));

...// データを初期化します

// データソースを追加します
workbook.AddDataSource("ds", datasource);

 

DataSet

DataSet とは、1つ以上の DataTable のコレクションです。

 

テンプレート構文:[データソースの別名].[テーブル名].[列名]

例:

{{ds.Table1.ID}}

{{ds.Table2.Team}}

 

DataSet のデータソースを連結

C#
コードのコピー
var Table1 = new System.Data.DataTable();
var Table2 = new System.Data.DataTable();

...// データを初期化します

var datasource = new System.Data.DataSet();
datasource.Tables.Add(Table1);
datasource.Tables.Add(Table2);

// データソースを追加します
workbook.AddDataSource("ds", datasource);

 

カスタムオブジェクト

カスタムオブジェクトとは、コードにてユーザーが定義したオブジェクト、または JSON 文字列/ファイル/XML などのシリアライズされたオブジェクトのことです。テンプレート構文では、カスタムオブジェクトとしてシリアライズできる任意のデータソースに対応しています。

 

テンプレート構文:[データソースの別名].[フィールド名] または [データソースの別名].[プロパティ名]

例:

{{ds.Sales.Area}}

{{ds.Sales.Name}}

 

カスタムオブジェクトのデータソースを連結

C#
コードのコピー
// カスタムクラスの定義 
public class SalesData
{
    public List<SalesRecord> Sales;
}

public class SalesRecord
{
    public string Area;
    public string City;
    public string Category;
    public string Name;
    public double Revenue;
}
C#
コードのコピー
var datasource = new SalesData
{
    Sales = new List<SalesRecord>()
};

var record1 = new SalesRecord
{
    Area = "北米",
    City = "シカゴ",
    Category = "家電製品",
    Name = "Bose 785593-0050",
    Revenue = 92800
};
datasource.Sales.Add(record1);

var record2 = new SalesRecord
{
    Area = "北米",
    City = "ニューヨーク",
    Category = "家電製品",
    Name = "Bose 785593-0050",
    Revenue = 92800
};
datasource.Sales.Add(record2);

...// データを初期化します

// データソースを追加します
workbook.AddDataSource("ds", datasource);

 

カスタムデータテーブル

ユーザー定義のカスタムテーブルは、任意タイプのデータベースからの行と列のコレクションです。DioDocs for Excelは、カスタムデータソースを簡単に作成し、より効率的に処理するためのITableDataSource インターフェースを提供します。以下の表は、ITableDataSourceインターフェースのすべてのメソッドの一覧です。

メソッド 説明
GetValue 行と列のインデックスに基づいて値を取得します。
GetRowCount 行数を取得します。
GetColumnCount 列数を取得します。
GetColumnName 列インデックスに基づいて列名を取得します。
GetColumnIndex 列名に基づいて列インデックスを取得します。

テンプレート構文

[[データソースの別名].[フィールド名]

または

[データソースの別名].[プロパティ名]

例:

{{customer.name}}

{{product.name}}

JSONストリームを構造化されたテーブルに変換するクラスを使用して、カスタムデータテーブルを作成する方法については、以下のサンプルコードを参照してください。

C#
コードのコピー
class Program
{
    static void Main(string[] args)
    {
        // Initialize Workbook.
        var workbook = new Workbook();

        // Open template file.
        workbook.Open("ComplexMultiDataSource.xlsx");

        // Create table data sources from JSON.
        Stream order_json = new FileStream("order.json", FileMode.Open);
        Stream customer_json = new FileStream("customer.json", FileMode.Open);
        Stream product_json = new FileStream("product.json", FileMode.Open);
        JsonTable order = new JsonTable(order_json);
        JsonTable customer = new JsonTable(customer_json);
        JsonTable product = new JsonTable(product_json);

        // Add data sources for template.
        workbook.AddDataSource("order", order);
        workbook.AddDataSource("customer", customer);
        workbook.AddDataSource("product", product);

        // Process the template.
        workbook.ProcessTemplate();

        // Set column width.
        workbook.Worksheets[0].Range["A:F"].ColumnWidth = 16;

        // Save to an Excel file.
        workbook.Save("CustomDataTable.xlsx");

    }
}

/*
The class is only part of the sample, not part of the product.
So it is not recommended to use this class in a production environment.
Please implement your own class that meets the requirements of the product.
*/
// Create a class to transform a JSON stream into a table and inherit ITableDataSource.
internal class JsonTable : ITableDataSource
{
    private readonly List<JsonElement> _jsonArray;
    private readonly Dictionary<int, string> _columnsMap;
    private readonly Dictionary<string, int> _reversedColumnsMap;

    public JsonTable(Stream inputStream)
    {
        string jsonContent;
        try
        {
            jsonContent = ConvertToString(inputStream);
        }
        catch (IOException e)
        {
            throw new Exception(e.Message, e);
        }

        _jsonArray = ToJsonArray(JsonDocument.Parse(jsonContent).RootElement.EnumerateArray());

        JsonElement jsonObject = _jsonArray[0];

        _columnsMap = new Dictionary<int, string>();
        _reversedColumnsMap = new Dictionary<string, int>();
        foreach (var property in jsonObject.EnumerateObject())
        {
            _columnsMap.Add(_columnsMap.Count, property.Name);
            _reversedColumnsMap.Add(property.Name, _reversedColumnsMap.Count);
        }
    }

    private List<JsonElement> ToJsonArray(ArrayEnumerator enumerator)
    {
        var jsonArray = new List<JsonElement>();
        while (enumerator.MoveNext())
        {
            jsonArray.Add(enumerator.Current);
        }
        return jsonArray;
    }

    private string ConvertToString(Stream inputStream)
    {
        using (StreamReader reader = new StreamReader(inputStream, Encoding.UTF8))
        {
            return reader.ReadToEnd();
        }
    }

    // Get column count from data source.
    public int GetColumnCount()
    {
        return _columnsMap.Count;
    }

    // Get column index from data source.
    public int GetColumnIndex(string columnName)
    {
        if (_reversedColumnsMap.TryGetValue(columnName, out int res))
        {
            return res;
        }

        return -1;
    }

    // Get column name from data source.
    public string GetColumnName(int column)
    {
        if (_columnsMap.TryGetValue(column, out string res))
        {
            return res;
        }

        return null;
    }

    // Get row count from data source.
    public int GetRowCount()
    {
        return _jsonArray.Count;
    }

    // Get value from data source.
    public object GetValue(int row, int column)
    {
        JsonElement jsonElement = _jsonArray[row].GetProperty(this.GetColumnName(column));

        switch (jsonElement.ValueKind)
        {
            case JsonValueKind.String:
                return jsonElement.GetString();
            case JsonValueKind.Number:
                return jsonElement.GetDouble();
            case JsonValueKind.True:
                return true;
            case JsonValueKind.False:
                return false;
            case JsonValueKind.Null:
            case JsonValueKind.Undefined:
            case JsonValueKind.Object:
            case JsonValueKind.Array:
            default:
                return null;
        }
    }
}

カスタムデータテーブルの詳細については、デモ demo をご参照ください。

 

JSON

DioDocs for Excel では、JsonDataSource クラスのインスタンスをカスタムオブジェクトとして作成できます。つまり、データソースとして JSON を使用する際、JSON ファイルから直接取得した JSON 文字列にて JsonDataSource クラスのインスタンスを作成し、そのインスタンスをデータソースとして指定することができます。

これにより、JSON からデータを取得するためのマッピングクラスを作成する必要がなくなり、以下のテンプレート構文のように、JSON のフィールドまたはメンバーを構文で直接指定できるようになります。

 

テンプレート構文:[データソースの別名].[フィールド名]

例:

{{ds.student.family.father.name}}

{{ds.student.family.father.occupation}}

{{ds.student.family.mother.name}}

JSONサンプル

{

  "student": [

    {

      "name": "Jane",

      "address": "101, Halford Avenue, Fremont, CA",

      "family": [

        {

          "father": {

            "name": "Patrick James",

            "occupation": "Surgeon"

          },

          "mother": {

            "name": "Diana James",

            "occupation": "Surgeon"

          }

        },

        {

          "father": {

            "name": "father James",

            "occupation": "doctor"

          },

          "mother": {

            "name": "mother James",

            "occupation": "teacher"

          }

        }

      ]

    },

    {

      "name": "Mark",

      "address": "101, Halford Avenue, Fremont, CA",

      "family": [

        {

          "father": {

            "name": "Jonathan Williams",

            "occupation": "Product Engineer"

          },

          "mother": {

            "name": "Joanna Williams",

            "occupation": "Surgeon"
          }

        }

      ]

    }

  ]

}

 

JSON のデータソースを連結

C#
コードのコピー
// JSON 文字列を読み込みます
var jsonText = File.OpenText("Template_FamilyInfo.json").ReadToEnd();

// JsonDataSource を作成します
var datasource = new JsonDataSource(jsonText);

// データソースを追加します
workbook.AddDataSource("ds", datasource);

 

変数

コードにてユーザーが定義した変数のことです。

 

テンプレート構文:[データソースの別名]

例:

{{cName}}

{{count}}

{{owner}}

 

変数のデータソースを連結

C#
コードのコピー
var className = "Class 3";
var count = 500;
 
// データソースを追加します
workbook.AddDataSource("cName", className);
workbook.AddDataSource("count", count);
workbook.AddDataSource("owner", "Hunter Liu");

 

配列またはリスト

コードにてユーザーが定義した配列またはリストのことです。

 

テンプレート構文

  1. 基本的な型(string、int、double など)の変数の配列またはリスト:[データソースの別名]
  2. カスタムオブジェクトの配列またはリスト:[データソースの別名].[フィールド名] または [データソースの別名].[プロパティ名]

例:

{{p.Name}}

{{p.Age}}

{{countries}}

{{numbers}}

 

配列またはリストのデータソースを連結

C#
コードのコピー
// カスタムクラスの定義
public class Person
{
    public string Name;
    public int Age;
}
C#
コードのコピー
int[] numbers = new int[] {10, 12, 8, 15};
List<string> countries = new List<string>() {"アメリカ", "日本", "イギリス", "インド"};

List<Person> peoples = new List<Person>();

Person p1 = new Person();
p1.Name = "Helen";
p1.Age = 12;
peoples.Add(p1);

Person p2 = new Person();
p2.Name = "Jack";
p2.Age = 23;
peoples.Add(p2);

Person p3 = new Person();
p3.Name = "Fancy";
p3.Age = 25;
peoples.Add(p3);

workbook.AddDataSource("p", peoples);
workbook.AddDataSource("countries", countries);
workbook.AddDataSource("numbers", numbers);

 

帳票テンプレートを保持したままの Excel 帳票作成

IWorkbook インターフェースの GenerateReport メソッドを使用すると、帳票テンプレートのワークブックを保持したまま、作成した Excel 帳票を新しいワークブックのインスタンスとして返します。また、このメソッドには、特定のワークシートのみを使用して Excel 帳票を作成できるオーバーロードもあります。

GenerateReport メソッドを使用して Excel 帳票を作成する方法については、以下のサンプルコードを参照してください。

C#
コードのコピー
// 帳票を作成し、新しいワークブックのインスタンスとして返します
IWorkbook report = workbook.GenerateReport();  
                        
// 指定されたワークシートのみの帳票を作成して返します
IWorkbook report = workbook.GenerateReport(workbook.Worksheets["Sales"]); 

詳細な方法については、デモを参照してください。

テンプレート処理のキャンセル

DioDocs for Excel では、CancellationToken型のパラメータを受け取るProcessTemplateメソッドのオーバーロードを使用して、ProcessTemplateメソッドをキャンセルできます。キャンセル要求はワークブックを所有していないスレッドによって送信されるため、キャンセルはスレッドセーフです。CancellationTokenSourceの次のメソッドを使用して、CancellationTokenにシグナルを送信できます。

メソッド 説明
Cancel ProcessTemplateメソッドを直ちにキャンセルします。
CancelAfter 特定の遅延時間後にProcessTemplateメソッドをキャンセルします。
Dispose 現在のインスタンスが使用しているすべてのリソースを解放します。

ProcessTemplateメソッドのオーバーロードは、次の条件が満たされた場合にテンプレート処理をキャンセルします。

メモ: 部分的に展開されたテンプレートを使用するか、テンプレートを以前の状態に戻すかを決定する必要があります。以前の状態に戻す場合は、ProcessTemplateメソッドを呼び出す前にワークブックをシリアル化し、処理をキャンセルした後に逆シリアル化する必要があります。

リクエストに応じて、またはタイムアウトに達した後にテンプレートの処理をキャンセルする方法については、以下のサンプルコードを参照してください。

C#
コードのコピー
// Create a new workbook.
var workbook = new GrapeCity.Documents.Excel.Workbook();

// Load template file from resource.
workbook.Open("Template_SalesDataGroup_DataTable.xlsx");

Console.WriteLine("Creating test data.");

// Add data to DataTable.
var datasource = new System.Data.DataTable();
datasource.Columns.Add(new DataColumn("Area", typeof(string)));
datasource.Columns.Add(new DataColumn("City", typeof(string)));
datasource.Columns.Add(new DataColumn("Category", typeof(string)));
datasource.Columns.Add(new DataColumn("Name", typeof(string)));
datasource.Columns.Add(new DataColumn("Revenue", typeof(double)));

var areas = new[] { "North America", "South America" };
var cities = new[] { "Chicago", "New York", "Santiago", "Quito", "Fremont", "Buenos Aires", "Medillin", "Minnesota" };
var categories = new[] { "Consumer Electronics", "Mobile" };
var category1NamePrefixes = new[] { "Bose ", "Canon ", "Haier ", "IFB ", "Mi ", "Sennheiser " };
var category2NamePrefixes = new[] { "iPhone ", "OnePlus ", "Redmi ", "Samsung " };

Random rand = new Random();
var rows = datasource.Rows;

// You can increase the loop count if the demo is too fast on your computer.
for (var i = 0; i < 50000; i++)
{
    var area = areas[rand.Next(0, areas.Length)];
    var city = cities[rand.Next(0, cities.Length)];
    var categoryId = rand.Next(0, categories.Length);
    var category = categories[categoryId];
    var names = (categoryId == 0) ? category1NamePrefixes : category2NamePrefixes;
    var name = names[rand.Next(0, names.Length)] + rand.Next(10, 10000).ToString();
    var revenue = rand.Next(10000, 100000);
    rows.Add(area, city, category, name, revenue);
}

// Add template global settings.
workbook.Names.Add("TemplateOptions.KeepLineSize", "true");

// Add data source.
workbook.AddDataSource("ds", datasource);

// Cancel data source binding when cancel key is pressed or timeout is reached.
using (CancellationTokenSource cancellation = new CancellationTokenSource())
{
    void cancelHandler(object sender, ConsoleCancelEventArgs e)
    {
        // Exit the process.
        e.Cancel = true;

        // Prevent entering cancelHandler when ProcessTemplate is completed or canceled.
#if NETCOREAPP3_0_OR_GREATER
        Console.CancelKeyPress -= cancelHandler;
#endif
        // Cancel when cancel key is pressed.
        cancellation.Cancel();
    };
    Console.CancelKeyPress += cancelHandler;

    // Cancel when timeout is reached.
    cancellation.CancelAfter(TimeSpan.FromSeconds(10));
    Console.WriteLine("Start ProcessTemplate.");
    try
    {
        workbook.ProcessTemplate(cancellation.Token);
        Console.WriteLine("ProcessTemplate finished.");
    }
    catch (OperationCanceledException ex) when (ex.CancellationToken == cancellation.Token)
    {
        Console.WriteLine("ProcessTemplate was canceled.");
    }

    // Prevent entering cancelHandler when ProcessTemplate is completed or canceled.
#if NETCOREAPP3_0_OR_GREATER
    Console.CancelKeyPress -= cancelHandler;
#endif
}

// Save the workbook.
workbook.Save("CancelTemplateProcessing.xlsx");