本篇博客介绍一下最近做的一个支持json、xml、yaml、toml四种文件格式相互转换的工具:schema-bridgion:github.com/hhk-png/schema-bridgion。以下是基本用法:
typescript
import { convert } from 'schema-bridgion'
const input = {
name: 'Alice',
age: 28,
email: 'alice@example.com'
}
const xml = convert(JSON.stringify(input), 'json', 'xml')
console.log(xml)
具体的使用方法可以查看github:https://github.com/hhk-png/schema-bridgion。
在实现相互转换时,库本身并没有直接解析和stringify这些具体的文件,而是基于解析这些文件的库,以JSON作为桥梁,来实现不同格式文件之间的转换。因为这些解析具体文件的库都支持将文本转换为json,并将json再转换回去,所以schema-bridgion的实现就是简单的调用这些库的API,选择了合适的库就能够极大的简化转换的流程。
对于json,很多语言本身或者语言的运行环境都支持对json的解析,所以直接采用了JSON.parse和JSON.stringify。
对于xml ,选择了fast-xml-parser( github.com/NaturalIntelligence/fast-xml-parser ),fast-xml-parser的github上首页表示他自己的性能非常高,这是选择他的一个原因。之前在做lingo-reader的时候就发现了这个库,但是发现的时候lingo-reader已经基本完成,不太想迁移了,所以lingo-reader现在使用的是xml2js的xml parser,将其inline到lingo-reader中。
对于yaml ,选择的是npm上的yaml( github.com/eemeli/yaml )。schema-bridgion选择将json作为IR,实际上是不完整的,因为无法处理注释节点和节点的顺序问题,json不支持注释,并且对应的库在解析文件的时候有可能造成原有节点相对顺序的错乱,并不能完整的将原本可以转换的信息信息完全转换过去。而yaml的内部实现可以解决这个问题,其内部将所有的子元素都转化成了一个对象,比如key、value、注释节点和schalar节点,这样做虽然牺牲了一些效率,但是获得了极大的可扩展性,对于注释节点,可以准确的表示注释节点的位置,以及注释对象应该包含的注释文本。
schema-bridgion一开始也是采用的yaml的实现思路,接用这些解析库,已经实现了各库的解析结果到schema-bridgion自定义的IR的转换,但是在要实现IR转换为对应库的AST,然后转换为文本的时候,发现将JSON作为IR可以将实现难度骤降,就选择了目前的更简单的实现方式,可以查看commit:83be9bfee21a184ea58ef11287f34336721c31af,在下一个commit:f1408ba5b07a9d291d98389fa480c64bb077bf2b中进行了重构。另一个选择JSON作为IR的原因,是在使用这些文件时还没遇到过要严格依赖注释节点的场景。
schema-bridgion定义的IR比较乱,也没有将键值对的key单独作为一个对象在IR中存在,这是一个不好的地方。
对于toml ,选择了smol-toml( github.com/squirrelchat/smol-toml ),在smol-toml的issue中,遇到的一个问题也是没法完全解析和序列化注释节点,其为了性能,并没有选择yaml的实现方式。
在json或者这些保存元数据的文件中,有很多基础的数据类型,这些数据类型都有很多表示形式。比如数字,有十六进制、八进制、科学计数法等多种形态,再比如日期,可以有UTC、ISO等格式,这些形式的类型在转换过程中应该以字符串存储还是以数字等形态存储,是需要进行统一的。这也是schema-bridgion下一步会做的方向。具体会通过options来实现。