JSON 對比

按結構而非按行對比兩份 JSON 文件,列出新增、刪除和修改的路徑,可選擇忽略陣列順序。全程在瀏覽器內執行。

按結構對比,而不是按行。 貼上兩份文件,即可得到逐路徑的新增、刪除、修改報告。由於比較的是解析後的值,重新排版或調整鍵順序都不會被算作差異。

差異

為什麼文本 diff 不適合 JSON

行級 diff 看到的是排版,不是含義

標準的行級 diff 把 JSON 當作散文處理。把檔案的縮排從 2 空格改成 4 空格,每一行都會被標記為已更改;把某個鍵從物件頂部挪到底部,會得到一處刪除加一處新增,儘管解析後的值一模一樣;把一個長陣列折成一行,整段都會亮起。

結構化 diff 會先解析兩邊,再遍歷得到的值。比較開始時排版、鍵順序和空白早已不復存在,因此能報告出來的只可能是資料本身的真實差異。這正是它的輸出足夠短、真的能讀完的原因。

用路徑而不是行號

這裡的每一處差異都對應一個路徑,例如 user.roles[2]meta.updated。路徑不會因為文件別處的改動而失效,行號會。所以你可以把同一份報告貼進工單或程式碼評審,一週後它依然指向正確的位置。

三種操作恰好對應樹上可能發生的三件事:左邊有而右邊沒有的鍵是刪除,反過來是新增,兩邊都有但值不同的鍵是修改。型別變化——某個欄位原本是數字 1,現在成了字串 "1"——同樣被報告為修改,而且很值得留意,因為這類問題是下游 bug 的常見來源,任何 schema 校驗都未必能攔住。

陣列與順序問題

陣列是結構化對比中最需要取捨的地方。預設採用按位置比較:左邊的下標 0 與右邊的下標 0 相比。對於步驟序列這類有序資料這是正確的,但對於本質是集合的列表就會得出誤導性的結果——只要元素換個順序,每個位置看上去都變了。

「忽略陣列順序」選項會在比較前遞迴地對兩邊的陣列排序,使其規範化,於是重排過的列表會被判為相等。標籤列表、許可權集合、沒有保證順序的查詢結果都適合開啟它。而只要元素位置本身有含義,就應該關掉——因為開啟之後,真正的順序錯誤會變得完全不可見。

開源說明:使用原生 JavaScript 實現,不依賴第三方庫。

常見問題

它和普通的文本 diff 有什麼不同?
文本 diff 比較的是行,所以重新縮排或調換鍵順序都會顯示為變更。本工具先解析兩邊,因此只報告資料上的真實差異。
+、- 和 ~ 分別代表什麼?
加號表示只在修改後文件中存在的路徑,減號表示只在原始文件中存在,波浪號表示兩邊都有但取值不同。
為什麼調換順序的陣列被判為已修改?
預設按位置逐一比較陣列,這對有序資料是正確的。若要按無序集合比較,請開啟「忽略陣列順序」。
物件裡的鍵順序有影響嗎?
沒有。物件按鍵比較,因此在物件內部移動欄位永遠不會產生差異。只有陣列元素的位置才對順序敏感。
數字變成字串會被標記出來嗎?
會。型別變化會被報告為修改,這是刻意的:1 和 "1" 在下游的行為差別很大,不標出來極易漏掉。
我的文件會被髮送到伺服器嗎?
不會。兩邊的解析與比較都在瀏覽器內完成,不上傳、不記錄、不儲存。