门多萨:使用堆栈机器计算高效的JSON差异

2020-10-31 01:11:11

当我们开始开发最近发布的功能时,我们需要一种在浏览器内存中保留文档编辑历史的重要部分的方法,以便能够快速响应不同的用户界面状态。当用户选择各种文档版本进行比较时,我们希望能够快速重建文档历史的特定部分。

对于文本差异,我们使用,我们只是假设有人会为JSON文档实现类似高效和紧凑的diff格式,但没有这样的运气。如果我们想要一个超级紧凑和快速应用的通用JSON diff格式,我们必须自己发明它。于是,用于结构化JSON文档的完全非人类可读的diff格式门多萨应运而生。

一种灵活的格式,可以在未来适应更高级的编码。

基于简单的操作(如保留、插入和删除文本),供人类阅读和理解。

即使源已稍有更改,也可以通过在已更改的每个部分周围包含一些上下文来应用。

现在,当您在代码开发上与人类协作并使用诸如git之类的东西来跟踪您的更改时,这是非常棒的。然而,它的不足之处在于以一种紧凑的方式表达结构化文档(如JSON)之间的差异,这种方式可以在网络上高效传输,并在浏览器内用JavaScript进行解析。

大多数diff格式都是人类可读的。以这两个文档为例,在这两个文档中,密钥和数组之间有一些更改:

如果其中两个提交,则它们之间的Git差异将表示为:

-left.json2020-10-06 21:49:06.000000000+0200+right.json2020-10-06 21:49:35.000000000+0200@@-1,9+1,9@@{";名称";:";鲍勃";,-";实验性_foobar";:{";key";:";123";},+";foobar";:{";key";:";123";},";值";:[+{";_key";:";ghi";},{";_key";:";abc";},-{";_key";:";def";},-{";_key";:";ghi";}+{";_Key";:";def";}]-}+}。

这使得人类在应用后一种变化时理解所发生的事情变得有些实际。但正如你所见,就纯数据而言,有很多重复在进行。而且,只用正负来表达所有的变化并不是很有效。

门多萨构建了将一个文档转换为另一个文档的最小配方。它真正要做的就是比较两个JSON文档,并找出将它们的差异表示为数组中的字符串和整数的最小方法。您可以使用此差异将第一个文档重建为另一个文档。

门多萨补丁由整数和字符串数组组成。整数是操作码(“操作码”的缩写),是对应于操作的8位数字。操作码将参数作为字符串、正数或JSON值(即:正在更改的实际数据)。可用操作码列表如下,请注意,10-18是前面几个操作码的组合:

门多萨从补丁中读取这些操作码,并从它们生成结果文档。根据补丁的不同,门多萨可能会选择不严格遵循操作码,而选择一条更简单的路径。例如,如果每个字段和值都已更改,则只需用新数据替换整个文档,而无需执行所有操作,效率会更高。或者,如果您有一个对象列表,其中一个对象已移动到另一个位置并更改了键值,门多萨将设法返回到原始位置,并以一种廉价的方式表示更改。

门多萨是在围棋中实现的,可以在这里找到。我们还制作了,您可以在您自己的应用程序中使用。

当然,您可以深入了解门多萨是如何在那里使用的。如果您想要稍微简单一点的用例,您还可以在浏览器中为提供支持。

给项目命名总是很困难的。因为这个项目的重点是表示JSON文档之间的更改,所以我自然开始考虑诸如JSON Different、JSON Changes、JSON patch、…之类的名称。";。然而,这些名称中的大多数已经被现有项目使用。当我喃喃地说着JSON,JSON,JSON&34;它突然变成了JSON,JSON,杰森,杰森·门多萨。

杰森·门多萨是电视剧“好地方”中的一个角色,虽然这个项目与佛罗里达州最愚蠢的DJ没有什么共同之处,但至少它简短而朗朗上口。

由于门多萨补丁只是描述更改的效果,因此它也仅限于用于它所基于的文档。如果在此期间应用它的文档已从原始文档更改,则它不会提供一致性保证。这是我们需要做的权衡之一,以使其真正压缩。