{"id":19437664,"url":"https://github.com/mganss/excelmapper","last_synced_at":"2025-05-13T21:10:52.269Z","repository":{"id":37814959,"uuid":"47032566","full_name":"mganss/ExcelMapper","owner":"mganss","description":"An Excel to object mapper. Maps POCOs to and from Excel. Configuration via convention, attributes, or fluent methods.","archived":false,"fork":false,"pushed_at":"2025-04-23T17:54:57.000Z","size":788,"stargazers_count":842,"open_issues_count":29,"forks_count":124,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-04-28T17:03:04.374Z","etag":null,"topics":["excel","mapper","npoi","orm","poco","xls","xlsx"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mganss.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-11-28T17:20:40.000Z","updated_at":"2025-04-27T10:38:38.000Z","dependencies_parsed_at":"2022-07-14T02:10:28.374Z","dependency_job_id":"2f73e6a5-d98c-45f9-91c3-8facc1b2e041","html_url":"https://github.com/mganss/ExcelMapper","commit_stats":{"total_commits":324,"total_committers":17,"mean_commits":"19.058823529411764","dds":0.6697530864197531,"last_synced_commit":"a9c29b1a13751d315161300b2323b2fa95b8391d"},"previous_names":[],"tags_count":219,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mganss%2FExcelMapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mganss%2FExcelMapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mganss%2FExcelMapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mganss%2FExcelMapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mganss","download_url":"https://codeload.github.com/mganss/ExcelMapper/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254029002,"owners_count":22002283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["excel","mapper","npoi","orm","poco","xls","xlsx"],"created_at":"2024-11-10T15:15:29.007Z","updated_at":"2025-05-13T21:10:47.253Z","avatar_url":"https://github.com/mganss.png","language":"C#","readme":"# ExcelMapper\n\n[![NuGet version](https://badge.fury.io/nu/ExcelMapper.svg)](http://badge.fury.io/nu/ExcelMapper)\n[![Build status](https://ci.appveyor.com/api/projects/status/tyyg8905i24qv9pg/branch/master?svg=true)](https://ci.appveyor.com/project/mganss/excelmapper/branch/master)\n[![codecov.io](https://codecov.io/github/mganss/ExcelMapper/coverage.svg?branch=master)](https://codecov.io/github/mganss/ExcelMapper?branch=master)\n[![netstandard2.0](https://img.shields.io/badge/netstandard-2.0-brightgreen.svg)](https://img.shields.io/badge/netstandard-2.0-brightgreen.svg)\n[![net462](https://img.shields.io/badge/net-462-brightgreen.svg)](https://img.shields.io/badge/net-462-brightgreen.svg)\n\nA library to map [POCO](https://en.wikipedia.org/wiki/Plain_Old_CLR_Object) objects to Excel files.\n\n## Features\n\n* Read and write Excel files\n* Uses the pure managed [NPOI](https://github.com/tonyqus/npoi) library instead of the [Jet](https://en.wikipedia.org/wiki/Microsoft_Jet_Database_Engine) database engine ([NPOI users group](https://t.me/npoidevs))\n* Map to Excel files using header rows (column names) or column indexes (no header row)\n* Map nested objects (parent/child objects)\n* Optionally skip blank lines when reading\n* Preserve formatting when saving back files\n* Optionally let the mapper track objects\n* Map columns to properties through convention, attributes or method calls\n* Use custom or builtin data formats for numeric and DateTime columns\n* Map formulas or formula results depending on property type\n* Map JSON\n* Fetch/Save dynamic objects\n* Use records\n* Provide custom object factories\n\n## Read objects from an Excel file\n\n```C#\nvar products = new ExcelMapper(\"products.xlsx\").Fetch\u003cProduct\u003e();\n```\n\nThis expects the Excel file to contain a header row with the column names. Objects are read from the first worksheet. If the column names equal the property names (ignoring case) no other configuration is necessary. The format of the Excel file (xlsx or xls) is autodetected.\n\n## Map to specific column names\n\n```C#\npublic class Product\n{\n  public string Name { get; set; }\n  [Column(\"Number\")]\n  public int NumberInStock { get; set; }\n  public decimal Price { get; set; }\n}\n```\n\nThis maps the column named `Number` to the `NumberInStock` property.\n\n## Map to column indexes\n\nColumn indexes start at 1.\n\n```C#\npublic class Product\n{\n    [Column(1)]\n    public string Name { get; set; }\n    [Column(Letter=\"C\")]\n    public int NumberInStock { get; set; }\n    [Column(4)]\n    public decimal Price { get; set; }\n}\n\nvar products = new ExcelMapper(\"products.xlsx\") { HeaderRow = false }.Fetch\u003cProduct\u003e();\n```\n\nNote that column indexes don't need to be consecutive. When mapping to column indexes, every property needs to be explicitly mapped through the `ColumnAttribute` attribute or the `AddMapping()` method. You can combine column indexes with column names to specify an explicit column order while still using a header row.\n\n## Map through method calls\n\n```C#\nvar excel = new ExcelMapper(\"products.xls\");\nexcel.AddMapping\u003cProduct\u003e(\"Number\", p =\u003e p.NumberInStock);\nexcel.AddMapping\u003cProduct\u003e(1, p =\u003e p.NumberInStock);\nexcel.AddMapping(typeof(Product), \"Number\", \"NumberInStock\");\nexcel.AddMapping(typeof(Product), ExcelMapper.LetterToIndex(\"A\"), \"NumberInStock\");\n```\n\n## Multiple mappings\n\nYou can map a single column to multiple properties but you need to be aware of what should happen when mapping back from objects to Excel. To specify the single property you want to map back to Excel, add `MappingDirections.ExcelToObject` in the `Column` attribute of all other properties that map to the same column. Alternatively, you can use the `FromExcelOnly()` method when mapping through method calls.\n\n```c#\npublic class Product\n{\n    public decimal Price { get; set; }\n    [Column(\"Price\", MappingDirections.ExcelToObject)]\n    public string PriceString { get; set; }\n}\n\n// or\n\nexcel.AddMapping\u003cProduct\u003e(\"Price\", p =\u003e p.PriceString).FromExcelOnly();\n```\n\n`Column` attributes are inherited by default, resulting in multiple mappings for a single overridden property if you add a `Column` attribute to the property in base\nand derived classes. To prevent this, set the `Inherit` property to false on the `Column` attribute in the base class.\n\n## Dynamic mapping\n\nYou don't have to specify a mapping to static types, you can also fetch a collection of dynamic objects.\n\n```c#\nvar products = new ExcelMapper(\"products.xlsx\").Fetch(); // -\u003e IEnumerable\u003cdynamic\u003e\nproducts.First().Price += 1.0;\n```\n\nThe returned dynamic objects are instances of `ExpandoObject` with an extra property called `__indexes__` that is a dictionary specifying the mapping from property names to\ncolumn indexes. If you set the `HeaderRow` property to `false` on the `ExcelMapper` object, the property names of the returned dynamic objects will match the Excel \"letter\" column names, i.e. \"A\" for column 1 etc.\n\n## Save objects\n\n```C#\nvar products = new List\u003cProduct\u003e\n{\n    new Product { Name = \"Nudossi\", NumberInStock = 60, Price = 1.99m },\n    new Product { Name = \"Halloren\", NumberInStock = 33, Price = 2.99m },\n    new Product { Name = \"Filinchen\", NumberInStock = 100, Price = 0.99m },\n};\n\nnew ExcelMapper().Save(\"products.xlsx\", products, \"Products\");\n```\n\nThis saves to the worksheet named \"Products\". If you save objects after having previously read from an Excel file using the same instance of `ExcelMapper` the style of the workbook is preserved allowing use cases where an Excel template is filled with computed data.\n\n## Track objects\n\n```C#\nvar products = new ExcelMapper(\"products.xlsx\").Fetch\u003cProduct\u003e().ToList();\nproducts[1].Price += 1.0m;\nexcel.Save(\"products.out.xlsx\");\n```\n\n## Ignore properties\n\n```C#\npublic class Product\n{\n    public string Name { get; set; }\n    [Ignore]\n    public int Number { get; set; }\n    public decimal Price { get; set; }\n}\n\n// or\n\nvar excel = new ExcelMapper(\"products.xlsx\");\nexcel.Ignore\u003cProduct\u003e(p =\u003e p.Price);\n```\n\n## Use specific data formats\n\n```C#\npublic class Product\n{\n    [DataFormat(0xf)]\n    public DateTime Date { get; set; }\n\n    [DataFormat(\"0%\")]\n    public decimal Number { get; set; }\n}\n```\n\nYou can use both [builtin formats](https://poi.apache.org/apidocs/org/apache/poi/ss/usermodel/BuiltinFormats.html) and [custom formats](https://support.office.com/en-nz/article/Create-or-delete-a-custom-number-format-78f2a361-936b-4c03-8772-09fab54be7f4). The default format for DateTime cells is 0x16 (\"m/d/yy h:mm\") and can be changed through the properties `DefaultDateFormat` and `DateFormat`.\n\nExplicitly set data formats override existing formats in an Excel file. Otherwise existing column and cell styles will be left untouched.\n\n## Map formulas or results\n\nFormula columns are mapped according to the type of the property they are mapped to: for string properties, the formula itself (e.g. \"A1+B1\") is mapped, for other property types the formula result is mapped. If you need the formula result in a string property, use the `FormulaResult` attribute.\n\n```C#\npublic class Product\n{\n    [FormulaResult]\n    public string Result { get; set; }\n}\n\n// or\n\nexcel.AddMapping\u003cProduct\u003e(\"Result\" p =\u003e p.Result).AsFormulaResult();\n```\n\nIf you want to save formulas you need to use the `FormulaAttribute` attribute or call `AsFormula()` if mapping manually. \nIt's not needed if you only want to map from Excel to objects (deserialize).\n\n```C#\npublic class Product\n{\n    [Formula]\n    public string Formula { get; set; }\n}\n\n// or\n\nexcel.AddMapping\u003cProduct\u003e(\"Formula\" p =\u003e p.Formula).AsFormula();\n```\n\n☝️ The string values of formula properties must not start with the `=` sign. So instead of `=A1+B1` set the property's value to `A1+B1`.\n\n## Custom mapping\n\nIf you have specific requirements for mapping between cells and objects, you can use custom conversion methods. Here, cells that contain the string \"NULL\" are mapped to null:\n\n```C#\npublic class Product\n{\n    public DateTime? Date { get; set; }\n}\n\nexcel.AddMapping\u003cProduct\u003e(\"Date\", p =\u003e p.Date)\n    .SetCellUsing((c, o) =\u003e\n    {\n        if (o == null) c.SetCellValue(\"NULL\"); else c.SetCellValue((DateTime)o);\n    })\n    .SetPropertyUsing(v =\u003e\n    {\n        if ((v as string) == \"NULL\") return null;\n        return Convert.ChangeType(v, typeof(DateTime), CultureInfo.InvariantCulture);\n    });\n```\n\n## Header row and data row range\n\nYou can specify the row number of the header row using the property `HeaderRowNumber` (default is 0). The range of rows that are considered rows that may contain data can be specified using the properties `MinRowNumber` (default is 0) and `MaxRowNumber` (default is `int.MaxValue`). The header row doesn't have to fall within this range, e.g. you can have the header row in row 5 and the data in rows 10-20.\n\n## JSON\n\nYou can easily serialize to and from JSON formatted cells by specifying the `Json` attribute or `AsJson()` method.\n\n```c#\npublic class ProductJson\n{\n    [Json]\n    public Product Product { get; set; }\n}\n\n// or\n\nvar excel = new ExcelMapper(\"products.xls\");\nexcel.AddMapping\u003cProductJson\u003e(\"Product\", p =\u003e p.Product).AsJson();\n```\n\nThis also works with lists.\n\n```c#\npublic class ProductJson\n{\n    [Json]\n    public List\u003cProduct\u003e Products { get; set; }\n}\n```\n\n## Name normalization\n\nIf the header cell values are not uniform, perhaps because they contain varying amounts of whitespace, you can specify a normalization function that will be applied to header cell\nvalues before mapping to property names. This can be done globally or for specific classes only.\n\n```c#\nexcel.NormalizeUsing(n =\u003e Regex.Replace(n, \"\\s\", \"\"));\n```\n\nThis removes all whitespace so that columns with the string \" First Name \" map to a property named `FirstName`.\n\n## Records\n\nRecords are supported. \nIf the type has no default constructor (as is the case for positional records) the constructor with the highest number of arguments is used to initialize objects. \nThis constructor must have a parameter for each of the mapped properties with the same name as the corresponding property (ignoring case). \nThe remanining parameters will receive the default value of their type.\n\n## Nested objects\n\nNested objects are supported and should work out of the box for most use cases. For example, if you have a sheet with columns Name, Street, City, Zip, Birthday, you can map\nto the following class hierarchy without any configuration:\n\n```c#\npublic class Person\n{\n    public string Name { get; set; }\n    public DateTime Birthday { get; set; }\n    public Address Address { get; set; }\n}\n\npublic class Address\n{\n    public string Street { get; set; }\n    public string City { get; set; }\n    public string Zip { get; set; }\n}\n\nvar customers = new ExcelMapper(\"customers.xlsx\").Fetch\u003cPerson\u003e();\n```\n\nThis works with records, too:\n\n```c#\npublic record Person(string Name, DateTime Birthday, Address Address);\npublic record Address(string Street, string City, string Zip);\n```\n\n## Object factories\n\nYou can specify a custom object factory for any type which will be used to create object instances for mapped properties of that type. This can be useful to handle cases where object creation is otherwise not possible (such as for properties that have interface types) or where you want to execute specific initialization logic.\n\n```c#\npublic class Person\n{\n    public string Name { get; set; }\n    public IAddress Address { get; set; }\n}\n\nexcel.CreateInstance\u003cIAddress\u003e(() =\u003e new Address());\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmganss%2Fexcelmapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmganss%2Fexcelmapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmganss%2Fexcelmapper/lists"}