Skip to content

一个将JSON数据转化为Table格式的工具,支持嵌套、数组。

License

Notifications You must be signed in to change notification settings

yetrun/json5-to-table

Repository files navigation

json5-to-table

最好用的 JSON 数据转化为表格结构的工具之一。

经过一系列的打磨之后,可以说 json5-to-table 是目前最方便的将 JSON 数据转化为表格的工具之一。 它支持:

  • 嵌套的 JSON 数据,包括任意深层次的数组、对象等。
  • 内建支持生成 HTML、Excel 格式。
  • 可定制表头。
  • 方便扩展,使用原生的 generateTable 函数可辅助生成任意格式。
  • 提供一个命令行工具可用于跨语言的开发。

安装

推荐使用 Yarn 或 NPM 安装:

// With Yarn
$ yarn add json5-to-table

// Or with NPM
$ npm install json5-to-table

亦可全局安装为了使用命令行工具:

// Global install with Yarn
$ yarn global add json5-to-table

// Or global install with NPM
$ npm install --global json5-to-table

也可以在浏览器内添加一个 script 标签(请替换 0.1.x 为正确的版本,发布的版本可在 Releases 中查看):

<script lang="javascript" src="https://github.com/yetrun/json5-to-table/releases/download/0.1.x/json5-to-table.js"></script>

默认支持生成 HTML 格式。如果需要生成 Excel 格式,需同时安装依赖包:

$ yarn add xlsx

使用

引入函数并调用

如果是通过 Yarn 或 NPM 安装,使用 CommonJS 或 ES6 语法引入函数,例如

import {
  generateTable,
  generateHTMLTable,
  generateExcel,
  parseDataToSchema
} from 'json5-to-table'

如果是在浏览器中使用,使用全局变量 JSON5_TO_TABLE

const {
  generateTable,
  generateHTMLTable,
  generateExcel,
  parseDataToSchema
} = JSON5_TO_TABLE

然后调用函数生成表格结构,例如以下是生成 HTML 格式的表格:

const data = [
  {
    name: 'Jim',
    age: 18,
    courses: [
      { name: 'Music', duration: '3 hours' },
      { name: 'Basketball', duration: '2 hours' }
    ]
  },
  {
    name: 'Lucy',
    age: 17,
    courses: [
      { name: 'Music', duration: '2 hours' },
      { name: 'Painting', duration: '2 hours and 30 minutes' },
      { name: 'Yoga', duration: '1 hour and 40 minutes' }
    ]
  }
]

const schema = [
  { title: 'Name', path: 'name' },
  { title: 'Age', path: 'age' },
  { title: 'Courses', path: 'courses', props: [
    { title: 'Course Name', path: 'name' },
    { title: 'Learning Duration', path: 'duration' }
  ] }
]

generateHTMLTable(data, schema)

如此生成的表格的样子如下:

Name Age Courses
Course Name Learning Duration
Jim 18 Music 3 hours
Basketball 2 hours
Lucy 17 Music 2 hours
Painting 2 hours and 30 minutes
Yoga 1 hour and 40 minutes
### 使用命令行工具

全局安装包以后,即可使用命令行工具 json5-to-table. 其用法如下:

// 查看帮助文档
$ json5-to-table -h

// 生成 HTML 格式的表格,表格输出到控制台
$ json5-to-table -d <data-file> -e <schema-file> -p <options-file>

// 生成 Excel 格式的表格,表格输出到控制台
$ json5-to-table -d <data-file> --excel

使用场景

  1. 可作为工具使用,通过命令行的方式生成 HTML 或 Excel 表格。
  2. 其支持管道,可接入到其他语言。

特别说明

  1. 文件支持 JSON5 格式。

  2. <data-file> 支持 All In One 格式。当不指定 <schema-file><options-file> 时,且 <data-file> 的内容是以下结构,则从 <data-file> 中获得 dataschemaoptions

    // <data-file> 内容
    {
      "data": [
        // ...
      ],
      "schema": [
        // ...
      ],
      "options": {
        // ...
      }
    }
  3. <data-file> 参数未指定时,从标准输入中读取内容。

定制表头结构

Schema 的作用

定制表头字段

现有一段数据:

const data = [
  { a: 1, b: 2, c: 3 },
  { a: 4, b: 5, c: 6 }
]

我希望只对字段 ab 生成表格,过滤调字段 c,这时可以用 Schema. Schema 的定义如下:

const schema = [
  { path: 'a' },
  { path: 'b' }
]

此时再调用 generateHTMLTable(data, schema),生成的表头将如下:

a b

title:定制表头文本

同样是以上的数据,我们希望以大写的 A 和 B 来显示表头,可通过配置 title 选项来实现:

const schema = [
  { title: 'A', path: 'a' },
  { title: 'B', path: 'b' }
]

除了常规的文本之外,title 还有以下两种特殊用法:

  1. title 未给出时,文本由 path 导出。例如 { path: 'a' }{ title: 'a', path: 'a' } 等价。
  2. title 等于空白字符串时, 但表头不占用行单元格。 借助这个特性,可实现标量数组的分行显示。具体可参见将长文本数组分行显示

path:定制列的属性提取路径

path 用于定制该列提取数据的路径,它其实支持多种用法,列举如下:

  • '':提取完整的数据。
  • 'a':提取字段 a.
  • 'a.b.c':依次提取字段 abc,中间能很好地处理数组。

props:定制嵌套属性

如果数据含有深层嵌套,这时可通过 props 选项定制深层的 schema. 一个示例如下:

const data = [
  { a: 1, b: { c: 2, d: 3 }},
  { a: 4, b: { c: 5, d: 6 }}
]
const schema = [
  { path: 'a' },
  { path: 'b', props: [
    { path: 'c' },
    { path: 'd' }
  ] }
]

此时再调用 generateHTMLTable(data, schema),表头将展现嵌套格式:

a b
c d

对数组的处理

在生成表格时,数组和对象不区分对待,对象可以看作含有当个元素的数组。为了理解如此,现举几个例子加以说明。

对于下面两个数据,它们生成的表格结构是一样的:

const data1 = { a: 1, b: 2, c: 3 }

const data2 = [
  { a: 1, b: 2, c: 3 }
]

即使内部字段是数组,它们的生成格式保持一致:

const data1 = [
  { a: 1, b: { c: 2, d: 3 } }
]

const data2 = [
  { a: 1, b: [
    { c: 2, d: 3 }
  ]}
]

下面用例子说明数组如何显示。首先给定内部含有两个元素的数组(字段 b):

const data = [
  { a: 1, b: [
    { c: 2, d: 3 },
    { c: 4, d: 5 }
  ]}
]

给定 Schema:

const schema = [
  { path: 'a' },
  { path: 'b', props: [
    { path: 'c' },
    { path: 'd' }
  ]}
]

生成的完整表格显示为:

a b
c d
1 2 3
4 5

数据推导表头

推导方式

任何生成表格结构的函数,包括 generateTablegenerateHTMLTablegenerateExcel 都包含两种用法:

  1. 显示指定 Schema,例如:

    generateHTMLTable(data, schema)
  2. 隐式推导 Schema,例如:

    generateHTMLTable(data, null, { parseDataToSchema: 'stack' })

这里讲一下两种推导的方式:stackflatten. 他们的区别在于如何处理嵌套表头。给出一条带嵌套的数据:

const data = [
  {
    a: 1,
    b: {
      c: 2, d: 3
    }
  }
]

使用 stack 生成的表头是:

generateHTMLTable(data, null, { parseDataToSchema: 'stack' })
a b
d

使用 flatten 生成的表头是:

generateHTMLTable(data, null, { parseDataToSchema: 'stack' })
a b.c b.d

默认使用的策略是 stack,也就是说

generateHTMLTable(data)

等效于

generateHTMLTable(data, null, { parseDataToSchema: 'stack' })

推导问题

虽然可以使用隐式推导,但我这里还是不推荐使用,最主要的原因是无法保证列的顺序。例如对于以下数据:

const data = [
  { a: 1, b: 2, c: 3 },
  { c: 4, b: 5, a: 6 }
]

无法保证列一定按照 abc 的顺序排列。 一方面依赖于浏览器的实现, 另一方面推导算法也不做任何保证。

因此一律推荐在任何时候显示地指定 Schema. 如果你对 Schema 不够了解,可通过 parseDataToSchema 函数先导出 Schema,再调整成自身需要的样子。详细技巧可参见使用 parseDataToSchema 了解 Schema 的用法

API

generateTable

定义

generateTable(data, schema, options)

描述

该函数生成的表格格式以 JS 对象表示,其主要作用是提供一种方便的中间格式,以便转化为其他格式。实质上,generateHTMLTablegenerateExcel 都是基于该函数快速开发出来的。

参数解释

  • data:任意 JavaScript 数据,包括数组、对象、数字、字符串、Null、Undefined 等。
  • schema:定制表头结构,其用法在前文有详细讲解。
  • options:选项对象,当前仅支持一个选项:
    • parseSchemaToData"stack""flatten".

示例

const data = [
  {
    a: 1,
    b: [
      { c: 2, d: 3 }
    ]
  },
  {
    a: 4,
    b: [
      { c: 5, d: 6 },
      { c: 7, d: 8 }
    ]
  }
]

const schema = [
  { path: 'a' },
  { path: 'b', props: [
    { path: 'c' },
    { path: 'd' }
  ] }
]

generateTable(data, schema)

显示输出为:

{
  header: [
    [
      { row: 1, col: 1, val: 'a', rowSpan: 2, colSpan: 1 },
      { row: 1, col: 2, val: 'b', rowSpan: 1, colSpan: 2 },
      undefined
    ],
    [
      undefined,
      { row: 2, col: 2, val: 'c', rowSpan: 1, colSpan: 1 },
      { row: 2, col: 3, val: 'd', rowSpan: 1, colSpan: 1 }
    ]
  ],
  body: [
    [
      { row: 3, col: 1, val: 1, rowSpan: 1, colSpan: 1 },
      { row: 3, col: 2, val: 2, rowSpan: 1, colSpan: 1 },
      { row: 3, col: 3, val: 3, rowSpan: 1, colSpan: 1 }
    ],
    [
      { row: 4, col: 1, val: 4, rowSpan: 2, colSpan: 1 },
      { row: 4, col: 2, val: 5, rowSpan: 1, colSpan: 1 },
      { row: 4, col: 3, val: 6, rowSpan: 1, colSpan: 1 }
    ],
    [
      undefined,
      { row: 5, col: 2, val: 7, rowSpan: 1, colSpan: 1 },
      { row: 5, col: 3, val: 8, rowSpan: 1, colSpan: 1 }
    ]
  ]
}

generateHTMLTable

定义

generateHTMLTable(data, schema, options)

作用

生成 HTML 表格源码,返回的格式是字符串。生成的 HTML 表格用到的标签包括 <table><thead><tbody><tr><th><td>,可为标签定制属性,包括 classstyle 及其他。

参数解释

  • dataschema:同 generateTable.
  • options:选项对象,除了支持 generateTable 的选项之外,还支持下列选项:
    • attributes: 声明标签用到的属性,具体用法看示例。

示例

// 添加标签属性
generateHTMLTable(data, schema, {
  attributes: {
    table: { class: 'c-table' }, 
    thead: { class: 'c-table-header' }, 
    tbody: { class: 'c-table-body' },
    tr: { class: 'c-table-row' },
    'thead.tr': { style: 'background: light-blue' },
    'tbody.tr': { style: 'background: cyan' },
    th: { class: 'c-header-cell' },
    td: { class: 'c-data-cell' }
  }
})

generateExcel

备注

需同时安装依赖包 xlsx.

定义

generateExcel(data, schema, options)

作用

生成 Excel 表格。

参数解释

  • dataschema:同 generateTable.
  • options:选项对象,除了支持 generateTable 的选项之外,还支持下列选项:
    • writeTo: 一个文件路径。

示例

// 写入到文件路径
generateExcel(data, schema, { writeTo: '/tmp/example.xlsx' })

// 写入到标准输出
generateExcel(data, schema, { writeTo: '/dev/stdout' })

parseDataToSchema

定义

parseDataToSchema(data, mode)

作用

通过数据推导出 Schema,支持两种推导方式。

参数解释

  • data:数据
  • mode:推导方式,支持两种推导方式 "stack""flatten". 其详细区别可参考数据推导表格部分。

使用技巧

显示标量数组

虽然很少见, 但如果我们遇到下面的数组数据:

const data = ['A', 'B', 'C']

默认情况下显示在一个格子里:

A,B,C

我们希望对他分行显示,这时可通过定制空白的 path 满足目的:

const schema = { title: 'Data', path: '' }

显示效果将是:

Data
A
B
C

将长文本数组分行显示

数组在单元格中显示文本使用的是 array.toString() 方法,[1, 2, 3] 的显示效果是 1,2,3. 如果遇到长文本数组,例如:

const data = {
  short: 1,
  long: [
    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
    "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
    "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
  ]
}

默认的显示方式将不够好。这时可通过定制 Schema 来实现数组的分行显示:

const schema = [
  { path: 'short' },
  { path: 'long', props: [
    { title: '', path: '' }
  ]}
]

显示效果将如下:

short long
1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

解释

这里用到 titlepath 的特殊用法。空字符串的 title 不占用表头的格子,空字符串的 path 提取完整数据。由于数据是数组,所以改为提取数组内的完整数据。

使用 parseDataToSchema 了解 Schema 的用法

有些同学刚开始可能不知道 Schema 的用法,这时可通过 parseDataToSchema 推导出 Schema 并在控制台打印出来,打印出来的结果可调整以满足自己的需要。

import { generateHTMLTable, parseDataToSchema } from '@yetrun/json-to-table'

const data = [
  // ...
]

// 查看 Schema
console.log(parseDataToSchema(data))

// 从控制台复制 Schema,并根据自己的需要调整
const schema = [
  // ...
]

// 显式应用 Schema 并生成表格
generateHTMLTable(data, schema)

贡献

可提交 PR 以改进本项目,亦可克隆源码进行二次开发。这里列出开发时常用到的命令:

# 运行单元测试
$ yarn test

# 构建和打包
$ yarn build

License