{"id":20596008,"url":"https://github.com/520mianxiangduixiang520/json-diff","last_synced_at":"2025-04-14T23:44:15.113Z","repository":{"id":57576274,"uuid":"357236219","full_name":"520MianXiangDuiXiang520/json-diff","owner":"520MianXiangDuiXiang520","description":"RFC 6902 的 Go 语言实现，An implementation of RFC6902 (https://tools.ietf.org/html/rfc6902) with Golang","archived":false,"fork":false,"pushed_at":"2021-10-07T15:55:59.000Z","size":2179,"stargazers_count":17,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-14T23:44:10.257Z","etag":null,"topics":["diff","json-diff","marshal","rfc-6902","unmarshal"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/520MianXiangDuiXiang520.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}},"created_at":"2021-04-12T15:02:19.000Z","updated_at":"2025-01-03T06:21:24.000Z","dependencies_parsed_at":"2022-08-28T18:01:12.229Z","dependency_job_id":null,"html_url":"https://github.com/520MianXiangDuiXiang520/json-diff","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/520MianXiangDuiXiang520%2Fjson-diff","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/520MianXiangDuiXiang520%2Fjson-diff/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/520MianXiangDuiXiang520%2Fjson-diff/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/520MianXiangDuiXiang520%2Fjson-diff/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/520MianXiangDuiXiang520","download_url":"https://codeload.github.com/520MianXiangDuiXiang520/json-diff/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248981259,"owners_count":21193143,"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":["diff","json-diff","marshal","rfc-6902","unmarshal"],"created_at":"2024-11-16T08:14:46.688Z","updated_at":"2025-04-14T23:44:15.086Z","avatar_url":"https://github.com/520MianXiangDuiXiang520.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Json-Diff\n\n[RFC 6902](https://tools.ietf.org/html/rfc6902) 的 Go 语言实现\n\n[![GoDoc](https://camo.githubusercontent.com/ba58c24fb3ac922ec74e491d3ff57ebac895cf2deada3bf1c9eebda4b25d93da/68747470733a2f2f676f646f632e6f72672f6769746875622e636f6d2f67616d6d617a65726f2f776f726b6572706f6f6c3f7374617475732e737667)](https://pkg.go.dev/github.com/520MianXiangDuiXiang520/json-diff)\n\n\u003ca title=\"Apache License 2.0\" target=\"_blank\" href=\"https://github.com/520MianXiangDuiXiang520/json-diff/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-red.svg?style=flat-square\"\u003e\u003c/a\u003e\n\n\u003ca href=\"https://goreportcard.com/badge/github.com/520MianXiangDuiXiang520/json-diff\"\u003e \u003cimg src=\"https://goreportcard.com/badge/github.com/520MianXiangDuiXiang520/json-diff\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://codeclimate.com/github/520MianXiangDuiXiang520/json-diff/maintainability\"\u003e\u003cimg src=\"https://api.codeclimate.com/v1/badges/ed575aea812a025dfcc9/maintainability\" /\u003e\u003c/a\u003e\n\n```shell\ngo get -u github.com/520MianXiangDuiXiang520/json-diff\n```\n\n## 功能：\n\n### 序列化与反序列化\n\n与官方 json 包的序列化和反序列化不同，官方包序列化需要指定一个 `interface{}`, 像：\n\n```go\npackage main\n\nimport \"json\"\n\nfunc main() {\n  jsonStr := \"{}\"\n  var jsonObj interface{}\n  node := json.Unmarshal(\u0026jsonObj, []byte(jsonStr))\n  // ...\n}\n```\n\n这样不方便编辑反序列化后的 json 对象， json-diff 可以将任意的 json 串转换成统一的 `JsonNode` 类型，并且提供一系列的增删查改方法，方便操作对象：\n\n```go\nfunc ExampleUnmarshal() {\n    json := `{\n        \"A\": 2,\n        \"B\": [1, 2, 4],\n        \"C\": {\n          \"CA\": {\"CAA\": 1}\n        }\n      }`\n    jsonNode := Unmarshal([]byte(json))\n    fmt.Println(jsonNode)\n}\n```\n\n### 差异比较\n\n通过对比两个 Json 串，输出他们的差异或者通过差异串得到修改后的 json 串\n\n```go\nfunc ExampleAsDiffs() {\n\tjson1 := `{\n        \"A\": 1,\n        \"B\": [1, 2, 3],\n        \"C\": {\n          \"CA\": 1\n        }\n      }`\n\tjson2 := `{\n        \"A\": 2,\n        \"B\": [1, 2, 4],\n        \"C\": {\n          \"CA\": {\"CAA\": 1}\n        }\n      }`\n\tres, _ := AsDiffs([]byte(json1), []byte(json2), UseMoveOption, UseCopyOption, UseFullRemoveOption)\n\tfmt.Println(res)\n}\n```\n\n```go\nfunc ExampleMergeDiff() {\n\tjson2 := `{\n        \"A\": 1,\n        \"B\": [1, 2, 3, {\"BA\": 1}],\n        \"C\": {\n          \"CA\": 1,\n          \"CB\": 2\n        }\n      }`\n\tdiffs := `[\n        {\"op\": \"move\", \"from\": \"/A\", \"path\": \"/D\"},\n        {\"op\": \"move\", \"from\": \"/B/0\", \"path\": \"/B/1\"},\n        {\"op\": \"move\", \"from\": \"/B/2\", \"path\": \"/C/CB\"}\n      ]`\n\tres, _ := MergeDiff([]byte(json2), []byte(diffs))\n\tfmt.Println(res)\n}\n```\n\n#### 输出格式\n\n输出一个 json 格式的字节数组，类似于：\n\n```json\n   [\n     { \"op\": \"test\", \"path\": \"/a/b/c\", \"value\": \"foo\" },\n     { \"op\": \"remove\", \"path\": \"/a/b/c\" },\n     { \"op\": \"add\", \"path\": \"/a/b/c\", \"value\": [ \"foo\", \"bar\" ] },\n     { \"op\": \"replace\", \"path\": \"/a/b/c\", \"value\": 42 },\n     { \"op\": \"move\", \"from\": \"/a/b/c\", \"path\": \"/a/b/d\" },\n     { \"op\": \"copy\", \"from\": \"/a/b/d\", \"path\": \"/a/b/e\" }\n   ]\n```\n\n其中数组中的每一项代表一个差异点，格式由 RFC 6902 定义，op 表示差异类型，有六种：\n\n1. `add`: 新增\n2. `replace`: 替换\n3. `remove`: 删除\n4. `move`: 移动\n5. `copy`: 复制\n6. `test`: 测试\n\n其中 move 和 copy 可以减少差异串的体积，但会增加差异比较的时间, 可以通过修改 `AsDiff()` 的 options 指定是否开启，options 的选项和用法如下：\n\n```go\n  // 返回差异时使用 Copy, 当发现新增的子串出现在原串中时，使用该选项可以将 Add 行为替换为 Copy 行为\n  // 以减少差异串的大小，但这需要额外的计算，默认不开启\n  UseCopyOption JsonDiffOption = 1 \u003c\u003c iota\n\n  // 仅在 UseCopyOption 选项开启时有效，替换前会添加 Test 行为，以确保 Copy 的路径存在\n  UseCheckCopyOption\n\n  // 返回差异时使用 Copy, 当发现差异串中两个 Add 和 Remove 的值相等时，会将他们合并为一个 Move 行为\n  // 以此减少差异串的大小，默认不开启\n  UseMoveOption\n\n  // Remove 时除了返回 path, 还返回删除了的值，默认不开启\n  UseFullRemoveOption\n```\n\n#### 相等的依据\n\n对于一个对象，其内部元素的顺序不作为相等判断的依据，如\n\n```json\n{\n  \"a\": 1,\n  \"b\": 2,\n}\n```\n\n和\n\n```json\n{\n  \"b\": 2,\n  \"a\": 1,\n}\n```\n\n被认为是相等的。\n\n对于一个列表，元素顺序则作为判断相等的依据，如：\n\n```json\n{\n  \"a\": [1, 2]\n}\n```\n\n和\n\n```json\n{\n  \"a\": [2, 1]\n}\n```\n\n被认为不相等。\n\n只有一个元素的所有子元素全部相等，他们才相等\n\n#### 原子性\n\n根据 RFC 6092，差异合并应该具有原子性，即列表中有一个差异合并失败，之前的合并全部作废，而 test 类型就用来在合并差异之前检查路径和值是否正确，你可以通过选项开启它，但即便不使用 test，合并也是原子性的。\n\njson-diff 在合并差异前会深拷贝源数据，并使用拷贝的数据做差异合并，一旦发生错误，将会返回 nil, 任何情况下都不会修改原来的数据。\n\n## 参考\n\n[https://github.com/flipkart-incubator/zjsonpatch](https://github.com/flipkart-incubator/zjsonpatch)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F520mianxiangduixiang520%2Fjson-diff","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F520mianxiangduixiang520%2Fjson-diff","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F520mianxiangduixiang520%2Fjson-diff/lists"}