İki JSON Dosyasını Karşılaştırma ve Nelerin Değiştiğini Bulma

İki JSON dosyasını karşılaştırmanın en hızlı yolu, her ikisini de yan yana bir diff aracına yapıştırmak, aynı şekilde biçimlendirmek ve vurgulanan satırları okumaktır. Zor kısım genellikle karşılaştırma değildir. Gürültüdür: yeniden sıralanmış anahtarlar, farklı girintiler ve kaçak sondaki virgüller, neredeyse özdeş iki dosyayı hiçbir ortak noktası yokmuş gibi gösterebilir.

Bu kılavuz, temiz ve güvenilir bir diff elde etmek için izlenecek adımları açıklar. JSON dosyalarının anlamsal olarak aynı kalırken kağıt üzerinde neden birbirinden uzaklaştığını, bilmeye değer birkaç yöntemi ve birlikte takip edebileceğiniz çalışmalı bir örneği ele alacağız. Sadece aracı istiyorsanız, JSON karşılaştırma sayfamız tüm bunları tarayıcıda yapar.

JSON dosyalarını karşılaştırmanın neden aldatıcı derecede zor olduğu

JSON, küçük ve katı bir dilbilgisine sahiptir (bkz. json.org adresindeki spec), ancak yazarlara metnin nasıl düzenleneceği konusunda çok fazla özgürlük tanır. İki dosya tamamen aynı nesneyi tanımlayabilir ve yine de bayt bayt farklı olabilir. Düz metin diff'i bunların hiçbirini bilmez, bu yüzden hepsini özenle işaretler.

Başlamadan önce içselleştirilmesi gereken şey şudur: JSON'da nesne anahtarlarının sırası yoktur. Spec (RFC 8259) bir nesneyi sırasız ad/değer çiftleri kümesi olarak tanımlar. Dolayısıyla {"name":"Ada","id":7} ve {"id":7,"name":"Ada"} eşittir; satır diff'i onları kırmızı ve yeşil renklerle boyasa bile.

Değişiklik gibi görünür, genellikle değildir
Diff'te gördüğünüzGerçek bir değişiklik mi?Ne yapmalı
Farklı sıradaki anahtarlarHayır, nesneler sırasızdırHer iki taraftaki anahtarları sırala
2 boşluk vs 4 boşluk girintiHayırHer iki tarafı aynı şekilde biçimlendir
Küçültülmüş vs güzel yazdırılmışHayırHer iki tarafı biçimlendir
Dosya sonundaki sondaki yeni satırHayırYoksay veya boşlukları kırp
"7" değerinin 7 olarak değişmesiEvet, dize vs sayıAraştır, bu gerçek bir değişiklik
Farklı sıradaki dizi öğeleriBelki, diziler sıralıdırSıralamanın burada önemli olup olmadığına karar ver

Son satır insanları şaşırtır. Diziler sırasını korur, nesneler korumaz. Dolayısıyla [1, 2, 3] ve [3, 2, 1] gerçekten farklıdır, ancak bir nesnenin içindeki anahtarlar serbestçe yer değiştirebilir. JavaScript'in tüm bunları nasıl ayrıştırdığına dair ayrıntıları öğrenmek isteyenler için MDN'de kapsamlı bir JSON nesnesi referansı bulunmaktadır.

JSON karşılaştırmanın dört yolu ve her birine ne zaman başvurulacağı

Tek bir en iyi yöntem yoktur. Dosyaların nerede bulunduğuna ve ne öğrenmek istediğinize bağlıdır. İşte yaygın seçeneklerin kıyaslaması.

YöntemEn iyi kullanımÇabaJSON'ı anlıyor mu?
Göz gezdirmeKüçük dosyalar, bir veya iki alanDüşükHayır, ayrıştırıcı sizsiniz
Çevrimiçi diff aracıHızlı kontroller, her yerden yapıştırmaDüşükBiçimlendir + anahtarları sırala ile evet
Komut satırı (jq, diff)Diskteki dosyalar, betik yazma, büyük dosyalarOrtaÖnce sıralarsanız evet
IDE veya git diffBir repodaki dosyalarCommit'lendiyse düşükVarsayılan olarak satır tabanlı

Çoğu kişi için bir tarayıcı aracı hız açısından kazanır çünkü kurulacak hiçbir şey yoktur ve bir log veya API çağrısından doğrudan kod parçacığı yapıştırabilirsiniz. Sorun biçimlendirme gürültüsüdür; bununla bir sonraki adımda ilgileneceğiz. Terminalde yaşıyorsanız, jq öğrenilmesi gereken araçtır ve önemli olan tek bayrağı göstereceğiz.

En hızlı temiz karşılaştırma, adım adım

Biri bana iki yapılandırma dosyası verip "ne farklı?" diye sorduğunda kullandığım rutin budur. Yaklaşık on beş saniye sürer.

  1. JSON karşılaştırma aracını açın.
  2. Orijinali sola, yeni sürümü sağa yapıştırın.
  3. Her iki tarafta da Biçimlendir'e tıklayarak aynı girinti stilini paylaşmalarını sağlayın.
  4. Anahtarları sırala (kanonikleştir) seçeneğini etkinleştirerek yeniden sıralanmış anahtarların değişiklik olarak görünmesini durdurun.
  5. Sonucu okuyun. Yeşil eklenmiş, kırmızı kaldırılmış demektir; değişen bir değer her birinden birer tane olarak gösterilir.

Üçüncü ve dördüncü adımlar tüm hilenin özüdür. Her iki dosya da aynı biçimde biçimlendirildiğinde ve anahtarları sıralandığında, vurgulanacak tek şey gerçekten değişen şeydir. Diff motorumuz Google'ın diff-match-patch üzerine inşa edilmiştir; önce satır satır karşılaştırır, bu sayede uzun dosyalarda bile hızlı kalır.

Çalışmalı bir örnek

Diyelim ki bir kullanıcı kaydındaki değişikliği inceliyorsunuz. İşte öncesi:

{
  "name": "Ada Lovelace",
  "role": "editor",
  "active": true,
  "seats": 3
}

Ve işte sonrası, bir ekip arkadaşının size ilettiği şekliyle:

{
  "active": true,
  "name": "Ada Lovelace",
  "role": "admin",
  "seats": 5,
  "team": "platform"
}

Bunları ham bir satır diff'ine bırakın; anahtarlar farklı sırada olduğundan neredeyse her satır taşınmış gibi görünür. Her ikisini biçimlendirin ve sıralayın, gerçek hikaye kısadır:

Gerçekte ne değişti
AlanÖnceSonraDeğişiklik
roleeditoradminDeğiştirildi
seats35Değiştirildi
teamplatformEklendi
nameAda LovelaceAda LovelaceDeğişiklik yok
activetruetrueDeğişiklik yok (sadece taşındı)

Üç gerçek düzenleme: bir rol yükseltmesi, bir koltuk sayısı ve yeni bir ekip alanı. Yeniden sıralama gürültüydü. editor'dan admin'e bu terfi, incelemede yakalamak istediğiniz türden bir şeydir ve yirmi satır yanlış pozitifin altına gömüldüğünde gözden kaçması kolaydır.

Komut satırında biçimlendirme gürültüsünü gidermek

Dosyalarınız zaten diskteyse, aynı "biçimlendir ve sırala" fikri iki kısa komutla çalışır. -S bayrağı jq'ya nesne anahtarlarını sıralamasını söyler; her ikisini de bu şekilde aktararak normalize etmek, düz diff'in dürüst olmasını sağlar:

jq -S . old.json > old.sorted.json
jq -S . new.json > new.sorted.json
diff old.sorted.json new.sorted.json

Artık diff yalnızca gerçekten değişen değerleri raporlar; çünkü her iki dosya da aynı girinti ve aynı anahtar sırasına sahiptir. Bu, tarayıcıda Biçimlendir ve anahtarları sırala seçeneğini tıklamanın terminal karşılığıdır.

Metin diff'i ve yapısal diff karşılaştırması

Yukarıdakilerin tümü metin diff'idir: hızlı, görsel ve değişikliği okuyan bir insan için mükemmeldir. Yapısal diff daha ileri gider ve değişikliği veri olarak tanımlar. Bunun standardı, RFC 6902'de tanımlanan JSON Patch'tir; düzenlemeleri belirli bir yolda replace ve add gibi işlemler olarak ifade eder. Değişikliği yalnızca bir kişinin görmesi değil, bir programın uygulaması gerektiğinde yapısal diff'e ihtiyaç duyarsınız. Günlük inceleme için, sıralanmış anahtarlara sahip bir metin diff'i fazlasıyla yeterlidir.

Dikkat edilmesi gereken yaygın tuzaklar

TuzakNeden ısırırÇözüm
Sayı hassasiyeti2^53 − 1 üzerindeki tam sayılar JavaScript'te hassasiyetini yitirirBüyük ID'leri dize olarak karşılaştırın; bkz. MAX_SAFE_INTEGER
Unicode kaçışları"café" ve "café" aynı dizedir, farklı baytlarHer iki tarafı biçimlendirin; bu kodlamayı normalleştirir
Yinelenen anahtarlarÇoğu ayrıştırıcı sessizce sonuncuyu tutarDiff'e güvenmeden önce JSON'ı doğrulayın
Sondaki virgüllerGeçerli JSON değil; bir dosya hiç ayrıştırılamayabilirÖnce sözdizimini düzeltin, doğrulayıcı bunu işaretleyecektir
Dize vs sayı"5" ve 5 benzer görünür ama farklı türlerdirBu gerçek bir değişikliktir, görmezden gelmeyin

İlgili araçlar

JSON nadiren uğraştığınız tek biçimdir. Ortamlar arasında yapılandırmayı karşılaştırıyorsanız, YAML karşılaştırma aynı fikri YAML'a uygular. İki API çağrısı arasındaki değişiklikleri incelemek için API yanıt diff'i aracı yapılmıştır ve bağımlılık güncellemelerini okumak package.json diff sayfasında en kolaydır.

Sıkça sorulan sorular

JSON dosyalarını çevrimiçi karşılaştırmak onları bir yere yüklüyor mu?
comparetext.org'da diff tarayıcınızda çalışır. İki JSON dosyası kendi makinenizdeki JavaScript tarafından karşılaştırılır, bu nedenle Kaydet veya Paylaş'a açıkça tıklamadığınız sürece hiçbir şey sunucuya gönderilmez. Bu onu yapılandırma dosyaları, API yanıtları ve her tuş vuruşunda yükleyen rastgele bir web sitesine yapıştırmak istemeyeceğiniz diğer veriler için güvenli kılar.
Neden iki JSON dosyam her satırı farklı gösteriyor?
Neredeyse her zaman biçimlendirmedir, gerçek değişiklikler değil. Bir dosya küçültülmüş veya sekmelerle girintili, diğeri iki boşlukla girintili ya da nesne anahtarları farklı sırada olabilir. Her iki tarafta da Biçimlendir'e tıklayarak aynı girintiyi kullanmalarını sağlayın, ardından anahtarları sıralayın; böylece sıra önemli olmaktan çıkar. Bundan sonra diff genellikle gerçekten değişen değerlerin küçük bir kısmına indirgenir.
Anahtar sırasını yoksayarak JSON'ı nasıl karşılaştırabilirim?
JSON nesne anahtarlarının tanımlanmış bir sırası yoktur, bu nedenle {"a":1,"b":2} ve {"b":2,"a":1} eşittir. Bir metin diff'inin de aynı fikirde olmasını sağlamak için, karşılaştırmadan önce her iki taraftaki anahtarları sıralayın. Tarayıcıda kanonikleştir (anahtarları sırala) seçeneğini kullanın. Komut satırında jq bunu yapar: jq -S . file.json. Her iki dosyanın anahtarları da aynı sıralanmış sırada olduğunda, yalnızca gerçek değer değişiklikleri görünür.
Sayfa donmadan büyük JSON dosyalarını karşılaştırabilir miyim?
Evet, bir noktaya kadar. Satır modu diff, her karakteri karşılaştırmak yerine önce tam satırları karşılaştırdığından binlerce satırlı dosyalarda hızlı kalır. Çok büyük dosyalar (birkaç megabayt) veriyi akışa alan jq veya git diff gibi bir komut satırı aracıyla daha iyi işlenir. Tarayıcıda rahatça kaydırabildiğiniz her şey için çevrimiçi bir diff daha hızlı bir seçenektir.
JSON'ın metin diff'i ile yapısal diff'i arasındaki fark nedir?
Metin diff'i dosyaları satır satır karşılaştırır, tıpkı iki makaleyi karşılaştırdığı gibi. Yapısal diff JSON'ı anlar, bu nedenle yeniden sıralanmış bir anahtarın değişiklik olmadığını ve bir dizinin içinde taşınan bir değerin silinmiş artı eklenmiş değil, taşınmış olduğunu bilir. Metin diff'leri daha hızlıdır ve çoğu inceleme için yeterlidir. Yapısal diff'ler (örneğin RFC 6902'ye göre JSON Patch) bir değişikliği bir programın uygulayabileceği veri olarak tanımlamanız gerektiğinde önem kazanır.
İki API yanıtını nasıl karşılaştırabilirim?
Her yanıtı bir dosyaya kaydedin veya tarayıcınızın ağ sekmesinden kopyalayın, ardından eski yanıtı sola, yeni olanı sağa yapıştırın. API'nin kararlı bir sırayla döndürmediği durumlarda her ikisini de biçimlendirin ve anahtarları sıralayın. api-response-diff aracı tam olarak bunun için ayarlanmıştır: iki çağrı arasında yeniden adlandırılmış bir alanı, değişen bir durum kodunu veya dizeden sayıya dönen bir değeri fark etmek.

Denemek ister misiniz? Dosyalarınızı JSON karşılaştırma aracına yapıştırın ve nelerin değiştiğini görün.