diff --git a/src/ExcelDataReader.DataSet/ExcelDataReaderExtensions.cs b/src/ExcelDataReader.DataSet/ExcelDataReaderExtensions.cs
index 9ac5b187..7dbfaa25 100644
--- a/src/ExcelDataReader.DataSet/ExcelDataReaderExtensions.cs
+++ b/src/ExcelDataReader.DataSet/ExcelDataReaderExtensions.cs
@@ -82,27 +82,45 @@ private static DataTable AsDataTable(IExcelDataReader self, ExcelDataTableConfig
configuration.ReadHeaderRow(self);
}
- for (var i = 0; i < self.FieldCount; i++)
+ if (configuration.ReadHeader != null)
{
- if (configuration.FilterColumn != null && !configuration.FilterColumn(self, i))
+ var dict = configuration.ReadHeader(self);
+ foreach (var kvp in dict)
{
- continue;
+ var columnIndex = kvp.Key;
+ var name = kvp.Value;
+
+ // if a column already exists with the name append _i to the duplicates
+ var columnName = GetUniqueColumnName(result, name);
+ var column = new DataColumn(columnName, typeof(object)) { Caption = name };
+ result.Columns.Add(column);
+ columnIndices.Add(columnIndex);
}
+ }
+ else
+ {
+ for (var i = 0; i < self.FieldCount; i++)
+ {
+ if (configuration.FilterColumn != null && !configuration.FilterColumn(self, i))
+ {
+ continue;
+ }
- var name = configuration.UseHeaderRow
- ? Convert.ToString(self.GetValue(i), CultureInfo.CurrentCulture)
- : null;
+ var name = configuration.UseHeaderRow
+ ? Convert.ToString(self.GetValue(i), CultureInfo.CurrentCulture)
+ : null;
- if (string.IsNullOrEmpty(name))
- {
- name = configuration.EmptyColumnNamePrefix + i;
- }
+ if (string.IsNullOrEmpty(name))
+ {
+ name = configuration.EmptyColumnNamePrefix + i;
+ }
- // if a column already exists with the name append _i to the duplicates
- var columnName = GetUniqueColumnName(result, name);
- var column = new DataColumn(columnName, typeof(object)) { Caption = name };
- result.Columns.Add(column);
- columnIndices.Add(i);
+ // if a column already exists with the name append _i to the duplicates
+ var columnName = GetUniqueColumnName(result, name);
+ var column = new DataColumn(columnName, typeof(object)) { Caption = name };
+ result.Columns.Add(column);
+ columnIndices.Add(i);
+ }
}
result.BeginLoadData();
diff --git a/src/ExcelDataReader.DataSet/ExcelDataTableConfiguration.cs b/src/ExcelDataReader.DataSet/ExcelDataTableConfiguration.cs
index 4fe58463..0b22489a 100644
--- a/src/ExcelDataReader.DataSet/ExcelDataTableConfiguration.cs
+++ b/src/ExcelDataReader.DataSet/ExcelDataTableConfiguration.cs
@@ -1,4 +1,4 @@
-namespace ExcelDataReader
+namespace ExcelDataReader
{
///
/// Processing configuration options and callbacks for AsDataTable().
@@ -20,6 +20,15 @@ public class ExcelDataTableConfiguration
///
public Action ReadHeaderRow { get; set; }
+ ///
+ /// Gets or sets a callback to allow a custom implementation of header reading.
+ /// The returned dictionary will be used to construct the resulting DataTable.
+ /// Each element of the dictionary specifies an index and column name pair.
+ /// An example use of this would be to combine multiple header rows.
+ /// NOTE: If this field is set, UseHeaderRow, EmptyColumnNamePrefix, and FilterColumn are ignored.
+ ///
+ public Func> ReadHeader { get; set; }
+
///
/// Gets or sets a callback to determine whether to include the current row in the DataTable.
///
diff --git a/test/ExcelDataReader.Tests/ExcelOpenXmlReaderTest.cs b/test/ExcelDataReader.Tests/ExcelOpenXmlReaderTest.cs
index 0879349b..4c6d1731 100644
--- a/test/ExcelDataReader.Tests/ExcelOpenXmlReaderTest.cs
+++ b/test/ExcelDataReader.Tests/ExcelOpenXmlReaderTest.cs
@@ -388,5 +388,69 @@ public void GitIssue425()
Assert.That(dataSet.Tables[0].Rows[1].ItemArray[0], Is.EqualTo("text"));
Assert.That(dataSet.Tables[0].Rows[2].ItemArray[0], Is.EqualTo("text text"));
}
+
+ [Test]
+ public void GitIssue518MultipleHeaderRows()
+ {
+ using (var reader = OpenReader("Test_git_issue_518"))
+ {
+ var dataSet = reader.AsDataSet(new ExcelDataSetConfiguration()
+ {
+ ConfigureDataTable = _ => new ExcelDataTableConfiguration()
+ {
+ UseHeaderRow = true,
+ ReadHeader = self =>
+ {
+ var headerNames = new List();
+
+ // read first header row
+ for (var i = 0; i < self.FieldCount; i++)
+ {
+ var s = Convert.ToString(self.GetValue(i));
+ headerNames.Add(s);
+ }
+
+ // append second header row
+ if (!self.Read()) {
+ throw new Exception();
+ }
+ var result = new Dictionary();
+ for (var i = 0; i < self.FieldCount; i++)
+ {
+ var first = headerNames[i];
+ var second = Convert.ToString(self.GetValue(i));
+ string name;
+ if (first.Length == 0)
+ {
+ name = second;
+ }
+ else if (second.Length == 0)
+ {
+ name = first;
+ }
+ else
+ {
+ name = first + " " + second;
+ }
+ if (string.IsNullOrEmpty(name))
+ {
+ name = "Column" + i;
+ }
+ result.Add(i, name);
+ }
+ return result;
+ }
+ }
+ });
+
+ var columns = dataSet.Tables[0].Columns;
+ Assert.That(columns[0].ColumnName.ToString(), Is.EqualTo("ColName1 A"));
+ Assert.That(columns[1].ColumnName.ToString(), Is.EqualTo("ColName1 B"));
+ Assert.That(columns[2].ColumnName.ToString(), Is.EqualTo("ColName2 B"));
+ Assert.That(columns[3].ColumnName.ToString(), Is.EqualTo("FirstOnly"));
+ Assert.That(columns[4].ColumnName.ToString(), Is.EqualTo("SecondOnly"));
+ Assert.That(columns[5].ColumnName.ToString(), Is.EqualTo("Another One"));
+ }
+ }
}
}
diff --git a/test/Resources/Test_git_issue_518.xlsx b/test/Resources/Test_git_issue_518.xlsx
new file mode 100644
index 00000000..1e678c96
Binary files /dev/null and b/test/Resources/Test_git_issue_518.xlsx differ