65.9K
CodeProject 正在变化。 阅读更多。
Home

从 Excel 工作表中提取 .NET 对象

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2018 年 3 月 22 日

CPOL

4分钟阅读

viewsIcon

16948

downloadIcon

311

描述了一种通用方法, 该方法从电子表格中提取给定类型的对象列表。

引言

本文演示了一种从 Excel 工作表或 Xml SpreadSheet 中获取 .NET 对象列表的快速方法,而不是 .NET Dataset/Datatable。此方法处理对象的 Enum 类型属性以及工作表数据不是从第 1 行第 1 列开始的情况。有时,用户需要在他们的应用程序中使用 Excel 工作表文件中的强类型对象列表,本文将帮助您以一种简单快速的方式实现这一目标。

背景

几个月前,我得到了一些 Excel 文件(另存为 Xml SpreadSheet 2003 格式),需要从中提取数据到 .NET 对象列表。 数据提取基于工作表的标题行或数据列位置/索引。 在我的例子中,为了序列化来自不同 XML 的不同对象,需要每次都进行编码。 为了摆脱这个问题,以下通用方法将对我们有所帮助。

要求:运行演示代码

  • .net framework 4.5 或更高版本
  • 需要 visual studio 2015 或更高版本。
  • 已在 (Microsoft Excel 2007) 上测试 *非强制

Using the Code

例如,假设我们有一个名为 PersonClass

    public class Person {
        public int ID { get; set; }
        public string Name { get; set; }
        public Nullable<System.DateTime> DateOfBirth { get; set; }
        public string District {get; set;}
    }

并且 Excel 文件(另存为 MS XML 格式 2003)看起来像这样

ExcelFile.xml

 <?xml version="1.0"?>

<Workbook >
 <Worksheet  Name="Sheet1">
  <Table>
   <Row>
    <Cell><Data  Type="String">ID</Data></Cell>
    <Cell><Data  Type="String">Name</Data></Cell>
    <Cell><Data  Type="String">DofB</Data></Cell>
    <Cell></Cell>
   </Row>
   <Row>
    <Cell><Data  Type="Number">1</Data></Cell>
    <Cell><Data  Type="String">A</Data></Cell>
    <Cell><Data  Type="DateTime">2010-09-28T00:00:00.000</Data></Cell>
    <Cell><Data  Type="String">District Z</Data></Cell>
   </Row>
   <Row>
    <Cell><Data  Type="Number">2</Data></Cell>
    <Cell><Data  Type="String">B</Data></Cell>
    <Cell><Data  Type="DateTime">2011-09-28T00:00:00.000</Data></Cell>
    <Cell><Data  Type="String">District Y</Data></Cell>
   </Row>
  </Table>
 </Worksheet>
</Workbook>

从输入 XML 文件中,我们看到一些数据行。 第 1st 行(索引 = 0)表示标题行,其余行是 Person 的数据行。 要从 XML 文件中获取 Person List

步骤 1

将下载的 *ExcelToObjectConvertor 项目*添加到您的解决方案,或者将 ExcelToObjectConvertor.dll 添加到您的项目中。 然后在要使用它的文件中包含它的命名空间。

using ExcelToObjectConvertor;

调用 ExcelXMLConvertor.GetWortSheetsInfo 方法。 这将给出所有工作表列表。 此列表包含工作表名称、工作表 Id 和其他信息。

string filePath = @"your excel file path"; 
List<WorkSheetInfo> workSheetList = ExcelXMLConvertor.GetWortSheetsInfo(filePath); 
or 
//for the file upload from fileUpload or OpenFileDialog
List<WorkSheetInfo> workSheetList = ExcelXMLConvertor.GetWortSheetsInfo(PostedFile.InputStream); 

从 workSheetList 中按名称或索引查找工作表,或者循环访问所有工作表以从中获取数据。

// Get data by workSheet name
WorkSheetInfo workSheet = workSheetList.Find(wh => wh.WorkSheetName == @"Sheet1");
//Update properties or Map object property to Column Name/Number of workSheet. 
//get data from workSheet.

Or

// Get data from all workSheet
foreach (WorkSheetInfo workSheet in workSheetList)
{
    //Update properties or Map object property to Column Name/Number of workSheet.
    //get data from workSheet.
}              

第二步

默认标题行索引为零 (HeaderRowIndex=0)。 您可以通过调用来更改标题行索引

ExcelXMLConvertor.UpdateHeaderRowIndexProperty(workSheet.WorkSheetId, newheaderRowIndex);

默认情况下,它会将 Header 行中的 Header 文本映射到对象属性名称。 例如,Person.Name 映射到第 1st<Row> 的第 2nd<cell>Person.ID 映射到第 1st<Row> 的第 1st<cell>

<Row>
  <Cell><Data Type="String">ID</Data></Cell>    //-->1st cell , cell position or column index = 0 
  <cell><Data  Type="String">Name</Data></cell> //-->2nd cell , cell position or column index = 1 
  ...
</Row>

所有第 1st 个单元格数据将映射到 Person.ID,第 2nd 个单元格数据将映射到 Person.Name

特殊情况

在我们的例子中,Person.DateOfBirth 无法映射到 XML 文件的 <Row> 节点的第 3rd<Cell>

<Row>
  ... 
  <cell><Data  Type="String">DofB</Data></cell> //-->3rd cell , cell position or column index = 2 
  ...
</Row>

Person.DateOfBirth 映射到第 3rd<cell> 节点,标题文本为 DofB

Person person = new Person();
ExcelXMLConvertor.MapPropertyNameToHeaderName(workSheet.WorkSheetId, 
                                             nameof(person.DateOfBirth), @"DofB");

所有 <row> 的最后一个 <cell> 节点都没有标题文本,因此它无法映射到任何类属性。 但是您可以将此 <cell> 节点与单元格位置或列索引映射,以便所有最后一个 <cell> 节点都映射到 Person.District。 为此,将最后一个 <cell>index = 3)映射到 Person.District

uint index = 3; 
ExcelXMLConvertor.MapPropertyNameToColumnNumber(workSheet.WorkSheetId, nameof(person.District),index);

*如果没有标题行,则必须将所有属性与列号映射。

步骤 3

最后,调用方法 ExcelXMLConvertor.GetObjectList<T>(WorkSheetId)

// Get data by workSheet name
List<Person> personList = ExcelXMLConvertor.GetObjectList<Person>(workSheet.WorkSheetId);

Or

// Get data from all workSheet if all workSheets have same type's data.
List<Person> personList = new List<Person>();;
foreach (WorkSheetInfo workSheet in workSheetList)
{
    personList.AddRange(ExcelXMLConvertor.GetObjectList<Person>(workSheet.WorkSheetId));
} 

代码执行后,PersonList 将有两个 person 对象

PersonList --> {Person(1, A, 2010-09-28, District Z), Person(2, B, 2011-09-28, District Y)}  

完整代码如下所示

using System;
using System.Xml;
using ExcelToObjectConvertor;
using System.Collections.Generic;
using System.IO;
using Excel = Microsoft.Office.Interop.Excel;

class Program
{
  static void Main(string[] args)
  {
     string filePath = Path.GetFullPath(@"Your File path");
     
     List<WorkSheetInfo> workSheetList= ExcelXMLConvertor.GetWortSheetsInfo(filePath);
     
     WorkSheetInfo workSheet = workSheetList.Find(wh => wh.WorkSheetName == @"Sheet1");
     Person person = new Person();
     ExcelXMLConvertor.MapPropertyNameToHeaderName(workSheet.WorkSheetId, 
                                         nameof(person.DateOfBirth), @"DofB");
     uint index = 3; 
     ExcelXMLConvertor.MapPropertyNameToColumnNumber(workSheet.WorkSheetId,
                                         nameof(person.District),index);
     //Result:
     List<Person> personList = ExcelXMLConvertor.GetObjectList<Person>(workSheet.WorkSheetId);
  }
}

使用示例 Web 应用程序

在我的演示项目中,我提供了一个示例 Web(aspx) 和控制台项目,以提供有关 ExcelToObjectConvertor 如何工作的想法。 以下图片将显示并解释它的工作原理。 运行演示 Web 项目,您会发现页面看起来像下图。

浏览您的 Excel 文件,然后单击“上传 Excel 文件”按钮上传它。 如果您不需要任何属性映射,只需从工作表下拉列表中选择一个工作表名称,从对象下拉列表中选择您要转换的对象名称(上图中未显示),然后单击“获取对象列表”按钮。 您将获得转换后的对象列表,该列表显示在页面底部。

标题行

默认情况下,第 1 行被检测为标题行,但用户可以从电子表格的前 5 行中选择一行作为标题行,从 First5Row 网格中选择。 如果没有标题行,则取消选中 HasHeader 复选框,并使用列号映射要加载数据的所有属性。 为此,选择列号单选按钮。 请参见下图

将属性映射到标题名称或单元格索引

从属性下拉列表中选择一个属性,从标题名称下拉列表中选择一个标题名称,然后单击“添加到映射对”按钮。 一个映射对将添加到映射对列表中。 您还可以通过选择“列号”单选按钮,插入一个索引(0 到 26),从“属性”下拉列表中选择适当的属性,然后单击“添加到映射对”按钮来将属性与列号/索引映射。

 

映射所有属性后,单击“获取对象列表”按钮。 请参见下面的示例输出

希望它能帮助一些人并减少工作量。

历史

  • 2018 年 3 月 22 日:初始版本
© . All rights reserved.