{"id":13813881,"url":"https://github.com/agrison/go-tablib","last_synced_at":"2025-03-06T10:37:36.092Z","repository":{"id":57480814,"uuid":"52277756","full_name":"agrison/go-tablib","owner":"agrison","description":"Go Module for Tabular Datasets in CSV, JSON, YAML, etc.","archived":false,"fork":false,"pushed_at":"2016-03-10T14:30:35.000Z","size":76,"stargazers_count":143,"open_issues_count":0,"forks_count":11,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-11-19T08:47:21.438Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","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/agrison.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-02-22T14:09:49.000Z","updated_at":"2024-01-06T08:39:23.000Z","dependencies_parsed_at":"2022-09-26T17:41:22.387Z","dependency_job_id":null,"html_url":"https://github.com/agrison/go-tablib","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agrison%2Fgo-tablib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agrison%2Fgo-tablib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agrison%2Fgo-tablib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agrison%2Fgo-tablib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agrison","download_url":"https://codeload.github.com/agrison/go-tablib/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242194585,"owners_count":20087610,"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":[],"created_at":"2024-08-04T04:01:34.319Z","updated_at":"2025-03-06T10:37:36.066Z","avatar_url":"https://github.com/agrison.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# go-tablib: format-agnostic tabular dataset library\n\n[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)][license]\n[![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs]\n[![Go Report Card](https://goreportcard.com/badge/github.com/agrison/go-tablib)][goreportcard]\n[![Build Status](https://travis-ci.org/agrison/go-tablib.svg?branch=master)](https://travis-ci.org/agrison/go-tablib)\n\n[license]: https://github.com/agrison/go-tablib/blob/master/LICENSE\n[godocs]: https://godoc.org/github.com/agrison/go-tablib\n[goreportcard]: https://goreportcard.com/report/github.com/agrison/go-tablib\n\nGo-Tablib is a format-agnostic tabular dataset library, written in Go.\nThis is a port of the famous Python's [tablib](https://github.com/kennethreitz/tablib) by Kenneth Reitz with some new features.\n\nExport formats supported:\n\n* JSON (Sets + Books)\n* YAML (Sets + Books)\n* XLSX (Sets + Books)\n* XML (Sets + Books)\n* TSV (Sets)\n* CSV (Sets)\n* ASCII + Markdown (Sets)\n* MySQL (Sets)\n* Postgres (Sets)\n\nLoading formats supported:\n\n* JSON (Sets + Books)\n* YAML (Sets + Books)\n* XML (Sets)\n* CSV (Sets)\n* TSV (Sets)\n\n\n## Overview\n\n### tablib.Dataset\nA Dataset is a table of tabular data. It must have a header row. Datasets can be exported to JSON, YAML, CSV, TSV, and XML. They can be filtered, sorted and validated against constraint on columns.\n\n### tablib.Databook\nA Databook is a set of Datasets. The most common form of a Databook is an Excel file with multiple spreadsheets. Databooks can be exported to JSON, YAML and XML.\n\n### tablib.Exportable\nAn exportable is a struct that holds a buffer representing the Databook or Dataset after it has been formated to any of the supported export formats.\nAt this point the Datbook or Dataset cannot be modified anymore, but it can be returned as a `string`, a `[]byte` or written to a `io.Writer` or a file.\n\n## Usage\n\nCreates a dataset and populate it:\n\n```go\nds := NewDataset([]string{\"firstName\", \"lastName\"})\n```\n\nAdd new rows:\n```go\nds.Append([]interface{}{\"John\", \"Adams\"})\nds.AppendValues(\"George\", \"Washington\")\n```\n\nAdd new columns:\n```go\nds.AppendColumn(\"age\", []interface{}{90, 67})\nds.AppendColumnValues(\"sex\", \"male\", \"male\")\n```\n\nAdd a dynamic column, by passing a function which has access to the current row, and must\nreturn a value:\n```go\nfunc lastNameLen(row []interface{}) interface{} {\n\treturn len(row[1].(string))\n}\nds.AppendDynamicColumn(\"lastName length\", lastNameLen)\nds.CSV()\n// \u003e\u003e\n// firstName, lastName, age, sex, lastName length\n// John, Adams, 90, male, 5\n// George, Washington, 67, male, 10\n```\n\nDelete rows:\n```go\nds.DeleteRow(1) // starts at 0\n```\n\nDelete columns:\n```go\nds.DeleteColumn(\"sex\")\n```\n\nGet a row or multiple rows:\n```go\nrow, _ := ds.Row(0)\nfmt.Println(row[\"firstName\"]) // George\n\nrows, _ := ds.Rows(0, 1)\nfmt.Println(rows[0][\"firstName\"]) // George\nfmt.Println(rows[1][\"firstName\"]) // Thomas\n```\n\nSlice a Dataset:\n```go\nnewDs, _ := ds.Slice(1, 5) // returns a fresh Dataset with rows [1..5[\n```\n\n\n## Filtering\n\nYou can add **tags** to rows by using a specific `Dataset` method. This allows you to filter your `Dataset` later. This can be useful to separate rows of data based on arbitrary criteria (e.g. origin) that you don’t want to include in your `Dataset`.\n```go\nds := NewDataset([]string{\"Maker\", \"Model\"})\nds.AppendTagged([]interface{}{\"Porsche\", \"911\"}, \"fast\", \"luxury\")\nds.AppendTagged([]interface{}{\"Skoda\", \"Octavia\"}, \"family\")\nds.AppendTagged([]interface{}{\"Ferrari\", \"458\"}, \"fast\", \"luxury\")\nds.AppendValues(\"Citroen\", \"Picasso\")\nds.AppendValues(\"Bentley\", \"Continental\")\nds.Tag(4, \"luxury\") // Bentley\nds.AppendValuesTagged(\"Aston Martin\", \"DB9\", /* these are tags */ \"fast\", \"luxury\")\n```\n\nFiltering the `Dataset` is possible by calling `Filter(column)`:\n```go\nluxuryCars, err := ds.Filter(\"luxury\").CSV()\nfmt.Println(luxuryCars)\n// \u003e\u003e\u003e\n// Maker,Model\n// Porsche,911\n// Ferrari,458\n// Bentley,Continental\n// Aston Martin,DB9\n```\n\n```go\nfastCars, err := ds.Filter(\"fast\").CSV()\nfmt.Println(fastCars)\n// \u003e\u003e\u003e\n// Maker,Model\n// Porsche,911\n// Ferrari,458\n// Aston Martin,DB9\n```\n\nTags at a specific row can be retrieved by calling `Dataset.Tags(index int)`\n\n## Sorting\n\nDatasets can be sorted by a specific column.\n```go\nds := NewDataset([]string{\"Maker\", \"Model\", \"Year\"})\nds.AppendValues(\"Porsche\", \"991\", 2012)\nds.AppendValues(\"Skoda\", \"Octavia\", 2011)\nds.AppendValues(\"Ferrari\", \"458\", 2009)\nds.AppendValues(\"Citroen\", \"Picasso II\", 2013)\nds.AppendValues(\"Bentley\", \"Continental GT\", 2003)\n\nsorted, err := ds.Sort(\"Year\").CSV()\nfmt.Println(sorted)\n// \u003e\u003e\n// Maker, Model, Year\n// Bentley, Continental GT, 2003\n// Ferrari, 458, 2009\n// Skoda, Octavia, 2011\n// Porsche, 991, 2012\n// Citroen, Picasso II, 2013\n```\n\n## Constraining\n\nDatasets can have columns constrained by functions and further checked if valid.\n```go\nds := NewDataset([]string{\"Maker\", \"Model\", \"Year\"})\nds.AppendValues(\"Porsche\", \"991\", 2012)\nds.AppendValues(\"Skoda\", \"Octavia\", 2011)\nds.AppendValues(\"Ferrari\", \"458\", 2009)\nds.AppendValues(\"Citroen\", \"Picasso II\", 2013)\nds.AppendValues(\"Bentley\", \"Continental GT\", 2003)\n\nds.ConstrainColumn(\"Year\", func(val interface{}) bool { return val.(int) \u003e 2008 })\nds.ValidFailFast() // false\nif !ds.Valid() { // validate the whole dataset, errors are retrieved in Dataset.ValidationErrors\n\tds.ValidationErrors[0] // Row: 4, Column: 2\n}\n```\n\nA Dataset with constrained columns can be filtered to keep only the rows satisfying the constraints.\n```go\nvalid := ds.ValidSubset().Tabular(\"simple\") // Cars after 2008\nfmt.Println(valid)\n```\n\nWill output:\n```\n------------  ---------------  ---------\n      Maker            Model       Year\n------------  ---------------  ---------\n    Porsche              991       2012\n\n      Skoda          Octavia       2011\n\n    Ferrari              458       2009\n\n    Citroen       Picasso II       2013\n------------  ---------------  ---------\n```\n\n```go\ninvalid := ds.InvalidSubset().Tabular(\"simple\") // Cars before 2008\nfmt.Println(invalid)\n```\n\nWill output:\n```\n------------  -------------------  ---------\n      Maker                Model       Year\n------------  -------------------  ---------\n    Bentley       Continental GT       2003\n------------  -------------------  ---------\n```\n\n## Loading\n\n### JSON\n```go\nds, _ := LoadJSON([]byte(`[\n  {\"age\":90,\"firstName\":\"John\",\"lastName\":\"Adams\"},\n  {\"age\":67,\"firstName\":\"George\",\"lastName\":\"Washington\"},\n  {\"age\":83,\"firstName\":\"Henry\",\"lastName\":\"Ford\"}\n]`))\n```\n\n### YAML\n```go\nds, _ := LoadYAML([]byte(`- age: 90\n  firstName: John\n  lastName: Adams\n- age: 67\n  firstName: George\n  lastName: Washington\n- age: 83\n  firstName: Henry\n  lastName: Ford`))\n```\n\n## Exports\n\n### Exportable\n\nAny of the following export format returns an `*Exportable` which means you can use:\n- `Bytes()` to get the content as a byte array\n- `String()` to get the content as a string\n- `WriteTo(io.Writer)` to write the content to an `io.Writer`\n- `WriteFile(filename string, perm os.FileMode)` to write to a file\n\nIt avoids unnecessary conversion between `string` and `[]byte` to output/write/whatever.\nThanks to [@figlief](https://github.com/figlief) for the proposition. \n\n### JSON\n```go\njson, _ := ds.JSON()\nfmt.Println(json)\n```\n\nWill output:\n```json\n[{\"age\":90,\"firstName\":\"John\",\"lastName\":\"Adams\"},{\"age\":67,\"firstName\":\"George\",\"lastName\":\"Washington\"},{\"age\":83,\"firstName\":\"Henry\",\"lastName\":\"Ford\"}]\n```\n\n### XML\n```go\nxml, _ := ds.XML()\nfmt.Println(xml)\n```\n\nWill ouput:\n```xml\n\u003cdataset\u003e\n \u003crow\u003e\n   \u003cage\u003e90\u003c/age\u003e\n   \u003cfirstName\u003eJohn\u003c/firstName\u003e\n   \u003clastName\u003eAdams\u003c/lastName\u003e\n \u003c/row\u003e  \u003crow\u003e\n   \u003cage\u003e67\u003c/age\u003e\n   \u003cfirstName\u003eGeorge\u003c/firstName\u003e\n   \u003clastName\u003eWashington\u003c/lastName\u003e\n \u003c/row\u003e  \u003crow\u003e\n   \u003cage\u003e83\u003c/age\u003e\n   \u003cfirstName\u003eHenry\u003c/firstName\u003e\n   \u003clastName\u003eFord\u003c/lastName\u003e\n \u003c/row\u003e\n\u003c/dataset\u003e\n```\n\n### CSV\n```go\ncsv, _ := ds.CSV()\nfmt.Println(csv)\n```\n\nWill ouput:\n```csv\nfirstName,lastName,age\nJohn,Adams,90\nGeorge,Washington,67\nHenry,Ford,83\n```\n\n### TSV\n```go\ntsv, _ := ds.TSV()\nfmt.Println(tsv)\n```\n\nWill ouput:\n```tsv\nfirstName lastName  age\nJohn  Adams  90\nGeorge  Washington  67\nHenry Ford 83\n```\n\n### YAML\n```go\nyaml, _ := ds.YAML()\nfmt.Println(yaml)\n```\n\nWill ouput:\n```yaml\n- age: 90\n  firstName: John\n  lastName: Adams\n- age: 67\n  firstName: George\n  lastName: Washington\n- age: 83\n  firstName: Henry\n  lastName: Ford\n```\n\n### HTML\n```go\nhtml := ds.HTML()\nfmt.Println(html)\n```\n\nWill output:\n```html\n\u003ctable class=\"table table-striped\"\u003e\n\t\u003cthead\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003cth\u003efirstName\u003c/th\u003e\n\t\t\t\u003cth\u003elastName\u003c/th\u003e\n\t\t\t\u003cth\u003eage\u003c/th\u003e\n\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003eGeorge\u003c/td\u003e\n\t\t\t\u003ctd\u003eWashington\u003c/td\u003e\n\t\t\t\u003ctd\u003e90\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003eHenry\u003c/td\u003e\n\t\t\t\u003ctd\u003eFord\u003c/td\u003e\n\t\t\t\u003ctd\u003e67\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003eFoo\u003c/td\u003e\n\t\t\t\u003ctd\u003eBar\u003c/td\u003e\n\t\t\t\u003ctd\u003e83\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n```\n\n### XLSX\n```go\nxlsx, _ := ds.XLSX()\nfmt.Println(xlsx)\n// \u003e\u003e\u003e\n// binary content\nxlsx.WriteTo(...)\n```\n\n### ASCII\n\n#### Grid format\n```go\nascii := ds.Tabular(\"grid\" /* tablib.TabularGrid */)\nfmt.Println(ascii)\n```\n\nWill output:\n```\n+--------------+---------------+--------+\n|    firstName |      lastName |    age |\n+==============+===============+========+\n|       George |    Washington |     90 |\n+--------------+---------------+--------+\n|        Henry |          Ford |     67 |\n+--------------+---------------+--------+\n|          Foo |           Bar |     83 |\n+--------------+---------------+--------+\n```\n\n#### Simple format\n```go\nascii := ds.Tabular(\"simple\" /* tablib.TabularSimple */)\nfmt.Println(ascii)\n```\n\nWill output:\n```\n--------------  ---------------  --------\n    firstName         lastName       age\n--------------  ---------------  --------\n       George       Washington        90\n\n        Henry             Ford        67\n\n          Foo              Bar        83\n--------------  ---------------  --------\n```\n\n#### Condensed format\n```go\nascii := ds.Tabular(\"condensed\" /* tablib.TabularCondensed */)\nfmt.Println(ascii)\n```\n\nSimilar to simple but with less line feed:\n```\n--------------  ---------------  --------\n    firstName         lastName       age\n--------------  ---------------  --------\n       George       Washington        90\n        Henry             Ford        67\n          Foo              Bar        83\n--------------  ---------------  --------\n```\n\n### Markdown\n\nMarkdown tables are similar to the Tabular condensed format, except that they have\npipe characters separating columns.\n\n```go\nmkd := ds.Markdown() // or\nmkd := ds.Tabular(\"markdown\" /* tablib.TabularMarkdown */)\nfmt.Println(mkd)\n```\n\nWill output:\n```\n|     firstName   |       lastName    |    gpa  |\n| --------------  | ---------------   | ------- |\n|          John   |          Adams    |     90  |\n|        George   |     Washington    |     67  |\n|        Thomas   |      Jefferson    |     50  |\n```\n\nWhich equals to the following when rendered as HTML:\n\n|     firstName   |       lastName    |    gpa  |\n| --------------  | ---------------   | ------- |\n|          John   |          Adams    |     90  |\n|        George   |     Washington    |     67  |\n|        Thomas   |      Jefferson    |     50  |\n\n### MySQL\n```go\nsql := ds.MySQL()\nfmt.Println(sql)\n```\n\nWill output:\n```sql\nCREATE TABLE IF NOT EXISTS presidents\n(\n\tid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,\n\tfirstName VARCHAR(9),\n\tlastName VARCHAR(8),\n\tgpa DOUBLE\n);\n\nINSERT INTO presidents VALUES(1, 'Jacques', 'Chirac', 88);\nINSERT INTO presidents VALUES(2, 'Nicolas', 'Sarkozy', 98);\nINSERT INTO presidents VALUES(3, 'François', 'Hollande', 34);\n\nCOMMIT;\n```\n\nNumeric (`uint`, `int`, `float`, ...) are stored as `DOUBLE`, `string`s as `VARCHAR` with width set to the length of the longest string in the column, and `time.Time`s are stored as `TIMESTAMP`.\n\n### Postgres\n```go\nsql := ds.Postgres()\nfmt.Println(sql)\n```\n\nWill output:\n```sql\nCREATE TABLE IF NOT EXISTS presidents\n(\n\tid SERIAL PRIMARY KEY,\n\tfirstName TEXT,\n\tlastName TEXT,\n\tgpa NUMERIC\n);\n\nINSERT INTO presidents VALUES(1, 'Jacques', 'Chirac', 88);\nINSERT INTO presidents VALUES(2, 'Nicolas', 'Sarkozy', 98);\nINSERT INTO presidents VALUES(3, 'François', 'Hollande', 34);\n\nCOMMIT;\n```\n\nNumerics (`uint`, `int`, `float`, ...) are stored as `NUMERIC`, `string`s as `TEXT` and `time.Time`s are stored as `TIMESTAMP`.\n\n## Databooks\n\nThis is an example of how to use Databooks.\n\n```go\ndb := NewDatabook()\n// or loading a JSON content\ndb, err := LoadDatabookJSON([]byte(`...`))\n// or a YAML content\ndb, err := LoadDatabookYAML([]byte(`...`))\n\n// a dataset of presidents\npresidents, _ := LoadJSON([]byte(`[\n  {\"Age\":90,\"First name\":\"John\",\"Last name\":\"Adams\"},\n  {\"Age\":67,\"First name\":\"George\",\"Last name\":\"Washington\"},\n  {\"Age\":83,\"First name\":\"Henry\",\"Last name\":\"Ford\"}\n]`))\n\n// a dataset of cars\ncars := NewDataset([]string{\"Maker\", \"Model\", \"Year\"})\ncars.AppendValues(\"Porsche\", \"991\", 2012)\ncars.AppendValues(\"Skoda\", \"Octavia\", 2011)\ncars.AppendValues(\"Ferrari\", \"458\", 2009)\ncars.AppendValues(\"Citroen\", \"Picasso II\", 2013)\ncars.AppendValues(\"Bentley\", \"Continental GT\", 2003)\n\n// add the sheets to the Databook\ndb.AddSheet(\"Cars\", cars.Sort(\"Year\"))\ndb.AddSheet(\"Presidents\", presidents.SortReverse(\"Age\"))\n\nfmt.Println(db.JSON())\n```\n\nWill output the following JSON representation of the Databook:\n```json\n[\n  {\n    \"title\": \"Cars\",\n    \"data\": [\n      {\"Maker\":\"Bentley\",\"Model\":\"Continental GT\",\"Year\":2003},\n      {\"Maker\":\"Ferrari\",\"Model\":\"458\",\"Year\":2009},\n      {\"Maker\":\"Skoda\",\"Model\":\"Octavia\",\"Year\":2011},\n      {\"Maker\":\"Porsche\",\"Model\":\"991\",\"Year\":2012},\n      {\"Maker\":\"Citroen\",\"Model\":\"Picasso II\",\"Year\":2013}\n    ]\n  },\n  {\n    \"title\": \"Presidents\",\n    \"data\": [\n      {\"Age\":90,\"First name\":\"John\",\"Last name\":\"Adams\"},\n      {\"Age\":83,\"First name\":\"Henry\",\"Last name\":\"Ford\"},\n      {\"Age\":67,\"First name\":\"George\",\"Last name\":\"Washington\"}\n    ]\n  }\n]\n```\n\n## Installation\n\n```bash\ngo get github.com/agrison/go-tablib\n```\n\nFor those wanting the v1 version where export methods returned a `string` and not an `Exportable`:\n```bash\ngo get gopkg.in/agrison/go-tablib.v1\n```\n\n## TODO\n\n* Loading in more formats\n* Support more formats: DBF, XLS, LATEX, ...\n\n## Contribute\n\nIt is a work in progress, so it may exist some bugs and edge cases not covered by the test suite.\n\nBut we're on Github and this is Open Source, pull requests are more than welcomed, come and have some fun :)\n\n## Acknowledgement\n\nThanks to kennethreitz for the first implementation in Python, [`github.com/bndr/gotabulate`](https://github.com/bndr/gotabulate), [`github.com/clbanning/mxj`](https://github.com/clbanning/mxj), [`github.com/tealeg/xlsx`](https://github.com/tealeg/xlsx), [`gopkg.in/yaml.v2`](https://gopkg.in/yaml.v2)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagrison%2Fgo-tablib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagrison%2Fgo-tablib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagrison%2Fgo-tablib/lists"}