🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Q&A

解決済

3回答

1693閲覧

JSONの構造が同じであることを検証したい

kata2murin

総合スコア22

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

0グッド

2クリップ

投稿2021/02/13 10:54

###実現したいこと
JavaScriptにてJSONを検証したいのですがお手伝い頂けませんでしょうか。

以下jsfiddle冒頭に書いたのですが、
https://jsfiddle.net/a19bvp4e/

var current_search_menus = {} について var default_search_menus = {} と同じ構造であることを検証したい

というのが目的です。

つまり、81行目のvalidate_current_search_menus()の書き方を知りたいのですが、どのように書くのがいいでしょうか。
###該当のソースコード
先のjsfiddleのソースコードになります。

jQuery

1/* 2 var current_search_menus = {} について 3 var default_search_menus = {} と同じ構造であることを検証したい 4 5 具体的な検証内容は次の2つ 6 7 【検証1】 8 default_search_menus に存在するキーだけで 9 current_search_menus が構成されていることを検証したい 10 (深い階層まで同じキーであることを検証したい) 11 12 【検証2】 13 search_pages:{この中} 14 の中に1つだけ "key": true があることを検証したい 15 16 【検証3】 17 posts:{この中}, comments:{この中}, users:{この中} 18 の中にそれぞれ1つずつ "key": true があることを検証したい 19*/ 20 21// 検証したい値(ユーザーが選択したラジオボタンがローカルストレージに保存されたもの) 22var current_search_menus = { 23 // 【検証1】default_search_menus と同じキーである 24 "search_pages": {"posts":true,"comments":false,"users":false}, // 【検証2】true は search_pages:{この中} に1つだけ 25 "search_filter": { 26 "posts": { 27 "dog": { 28 "a": false, // 【検証3】true は posts:{この中} の中に1つだけ 29 "n": true, 30 } 31 }, 32 "comments": { 33 "cat": { 34 "c": true, // 【検証3】true は comments:{この中} の中に1つだけ 35 } 36 }, 37 "users": { 38 "giraffe": { 39 "a": false, 40 "r": true, // 【検証3】true は users:{この中} の中に1つだけ 41 "v": false, 42 }, 43 "frog": { 44 "r": false, 45 "t": false, 46 }, 47 }, 48 } 49}; 50 51// デフォルトの値(PHPからprintしてJSで変数として持っている値) 52var default_search_menus = { 53 "search_pages": {"posts":false,"comments":false,"users":true}, 54 "search_filter": { 55 "posts": { 56 "dog": { 57 "a": true, 58 "n": false, 59 } 60 }, 61 "comments": { 62 "cat": { 63 "c": true, 64 } 65 }, 66 "users": { 67 "giraffe": { 68 "a": true, 69 "r": false, 70 "v": false, 71 }, 72 "frog": { 73 "r": false, 74 "t": false, 75 }, 76 }, 77 } 78}; 79 80// 検証を実行 81function validate_current_search_menus(current_search_menus){ 82 83 // 現状はわからないのでランダムに返す 84 var b = [true,false]; 85 var is_all_ok = Math.floor( Math.random() * b.length ); 86 return is_all_ok; 87 88} 89 90// ユーザーが選択した項目を取得 91var result = get_selected_search_menu(current_search_menus); 92console.log('result=',result); 93function get_selected_search_menu(current_search_menus){ 94 95 /* 96 このタイミングで【検証1、2、3】を実行すべく 97 validate_current_search_menus を通し 98 current_search_menus が正しいかどうか 99 ( is_all_ok = true かどうか ) を確認します 100 101 もし正しくなければ ( is_all_ok = false なら ) 102 current_search_menus でなく 103 default_search_menus を使って以下の処理を続けるようにしたいです 104 */ 105 const is_all_ok = validate_current_search_menus(current_search_menus); 106 if( is_all_ok ){ 107 search_menus = current_search_menus; 108 }else{ 109 search_menus = default_search_menus; 110 } 111 112 let result = {}; 113 114 let search_page = ''; 115 const search_pages = search_menus.search_pages; 116 $.each(search_pages, function(page_name,state){ 117 if(state === true){ 118 search_page = page_name; 119 } 120 }); 121 122 const search_filter = search_menus.search_filter[search_page]; 123 $.each(search_filter, function(name,obj){ 124 $.each(obj, function(kind,state){ 125 if(state === true){ 126 result = {name,kind}; 127 } 128 }); 129 }); 130 131 return result; 132} 133 134

###試したこと
81行目のvalidate_current_search_menus()ですが、自分なりにキーを一つずつcheck_same_keysで検証するという方法で書いてみました。

しかし、
・最後のis_single_trueだけがうまくいきません…
・そしてコードが冗長すぎて嫌になってきます…
ので、この2点の改善のお願いできればと思っています。

jQuery

1 2// 検証を実行 3function validate_current_search_menus(current_search_menus){ 4 5 // 現状はわからないのでランダムに返す 6 // var b = [true,false]; 7 // var is_ok = Math.floor( Math.random() * b.length ); 8 // return is_ok; 9 10 // キーが同じであることを確認 11 const check_same_keys = function(target_obj,default_obj){ 12 const current_keys = Object.keys(target_obj); 13 const default_keys = Object.keys(default_obj); 14 const is_same_keys = JSON.stringify(current_keys.sort()) === JSON.stringify(default_keys.sort()); 15 return is_same_keys; 16 } 17 18 // 【検証1】 19 const is_same_keys0 = check_same_keys(current_search_menus.search_filter,default_search_menus.search_filter) 20 console.log('is_same_keys0=',is_same_keys0); 21 22 const is_same_keys1 = check_same_keys(current_search_menus,default_search_menus); 23 console.log('is_same_keys1=',is_same_keys1); 24 25 let is_same_keys2 = false, 26 is_same_keys3 = false; 27 28 const ok_search_page_arr = Object.keys(default_search_menus.search_filter); 29 ok_search_page_arr.forEach(function(search_page){ 30 const target_search_filter = current_search_menus.search_filter[search_page]; 31 const default_search_filter = default_search_menus.search_filter[search_page]; 32 const is_same_keys2 = check_same_keys(target_search_filter,default_search_filter); 33 console.log('is_same_keys2=',is_same_keys2); 34 35 $.each(target_search_filter, function(name,obj){ 36 const default_obj = default_search_menus.search_filter[search_page][name]; 37 const is_same_keys3 = check_same_keys(obj,default_obj); 38 console.log('is_same_keys3=',is_same_keys3); 39 }); 40 }); 41 42 // 【検証2、3】 43 let is_single_true = true; 44 ok_search_page_arr.forEach(function(search_page){ 45 const search_filter = current_search_menus.search_filter[search_page]; 46 $.each(search_filter, function(name,obj){ 47 let count_true = 0; 48 $.each(obj, function(kind,state){ 49 if(state === true){ 50 count_true = count_true + 1; 51 } 52 }); 53 if( count_true !== 1 ){ 54 is_single_true = false; 55 return; 56 } 57 console.log('count_true=',count_true); // ここが1なのになぜか is_single_true=false になってしまう 58 }); 59 }); 60 console.log('is_single_true=',is_single_true); 61 62 const is_all_ok = is_same_keys0 && is_same_keys1 && is_same_keys2 && is_same_keys3 && is_single_true; 63 return is_all_ok; 64 65}

お時間ございましたらご回答いただけますと幸いです。
どうぞ宜しくお願い致します。

###条件
・jQueryだけで実装したいということもなく、JavaScriptでも問題ございません。
・外部のライブラリ(JSONスキーマなど)は使用せずに実装したいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hentaiman

2021/02/13 11:23

構造とキー名の大文字小文字が一致しているかどうかさえ分かれば良いのか、差異のある個所を抽出したいのか
kata2murin

2021/02/13 12:01

失礼致しました。抽出は不要です。一致しているかどうかさえ分かれば、あとは次の処理の流れだけを考えているためです。 > もし正しくなければ ( is_all_ok = false なら ) > current_search_menus でなく > default_search_menus を使って以下の処理を続けるようにしたいです
退会済みユーザー

退会済みユーザー

2021/02/13 13:59 編集

下記の2つのオブジェクトは「構造が同じ」と判定する、という理解でよろしいでしょうか。 {a:{b:1}, x:{y:2}}  と  {x:{y:5}, a:{b:0}}   [順序が異なるが、すべての値に対して同じ記述でアクセス可能]
kata2murin

2021/02/14 00:20

失礼致しました。おっしゃる通り順序は問題視せず「構造が同じ」と判定して頂いて結構です。(ただし値の方は、1, 2, 5, 0 のような値ではなく、{}, true, false の3つになりますが。)
hentaiman

2021/02/14 02:03

それは大抵の人は構造が違うと言うんじゃないかな・・・
guest

回答3

0

ベストアンサー

そもそも再帰しながら構造をチェックする関数を作れば一発解決な上に後々使い回しが効くかと。

function compareJSONTree(a,b) { if( b == undefined )retrn false;//←ここを追加 if( typeof(a) != "object" || typeof(b) != "object" )return (typeof(a)=="object") == (typeof(b)=="object"); if( Array.isArray(a) != Array.isArray(b) )return false; const keys = Object.keys(a); if( keys.length != Object.keys(b).length )return false; return keys.every(key=>compareJSONTree(a[key],b[key])); } compareJSONTree(current_search_menus,default_search_menus);

※追記
検証2,3についてはこんな感じでしょうか。
投げっぱなしになってしまいますが、下記サイトの内容が色々役に立つので、よろしければどうぞ。
MDN Array
MDN Object

javascript

1function check2() 2{ 3 return Object.values(default_search_menus.search_pages) 4 .filter(v=>v===true) 5 .length == 1; 6} 7 8function check3() 9{ 10 return ["posts","comments","users"].every(key=> 11 { 12 return Object.values(default_search_menus.search_filter[key]) 13 .filter(child=> 14 { 15 return Object.values(child).filter(v=>v===true).length == 1; 16 }) 17 .length == 1; 18 }); 19}

※更に追記
compareJSONTreeで、引数bがundefinedである場合に対応できていない問題に対処しました。
compareJSONTreeの先頭にif( b == undefined )return false;を追加して下さい。

投稿2021/02/13 13:10

編集2021/02/14 02:58
AT_2nd

総合スコア266

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kata2murin

2021/02/13 13:20

こう使いまわしが効くのは最高ですね。どうもありがとうございます。保存版です。 あとは【検証3】の「> is_single_true=false になってしまう」という問題が残っていて、他の方には簡単だろと言われてしまいましたが、これが質問のようになかなか…
kata2murin

2021/02/14 00:16

おはようございます。2と3完ぺきでした。どうもありがとうございます。MDNリンクは読んでいたのですが、AT_2nd様のように応用できるレベルまでいくにはなかなか難しいです…
kata2murin

2021/02/14 00:17

ところで、先ほどの1の compareJSONTree() ですが、最深部のキーだけチェックが機能しないようでした。 下記は validate_current_search_menus() に123を入れたものでして、 https://jsfiddle.net/tg1moeu5/ 例えば27行目の "dog": { "a": false, "n": true, } という部分を "dog": { "b": false, "n": true, } というキーにしても、検証が true で通ってしまいます。 なぜ最深部だけ機能しないかだけ最後に教えていただけませんでしょうか。
AT_2nd

2021/02/14 02:59

回答に追記しました。
kata2murin

2021/02/14 03:04

なるほど。再帰しているからそこにそれだけ書けば済んだのですね。再帰が初めてでかなり悩んでしまいました。重ねてどうもありがとうございます。
guest

0

物凄く雑の処理の流れだけ言うと

var jsonA = {"keyA":1}; var jsonB = {"keyA":2};

の二つのjsonがある場合に

jsonA = {"keyA":null}; jsonB = {"keyA":null};

と言うように、オブジェクト以外の全ての要素の値をnullにして(1でもfalseでも何でも良いけど)、JSON.stringfy()で比較します

if( JSON.stringify(jsonA) == JSON.stringify(jsonB)){ //onaji }

nullにする為の再帰関数を作る手間だけ必要です。
雑に型まで判定するならnullにする代わりにtypeofの結果を入れます

投稿2021/02/13 12:32

hentaiman

総合スコア6426

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kata2murin

2021/02/13 12:44

おもしろい工夫ですね。【検証1】はそれでできそうです。 あとは【検証3】の「> is_single_true=false になってしまう」という問題が残りますので、引き続き別の方に期待させて頂きます。 ありがとうございました。
hentaiman

2021/02/13 12:53

それこそ再帰関数の中でちょっと判定処理追加するだけだと思いますが。
guest

0

少し面倒かもしれませんがcurrent_search_menusdefault_search_menusのキーを抽出して、各階層ごとに比較するのはどうでしょうか

javascript

1a_key = Object.keys(current_search_menus); 2b_key = Object.keys(default_search_menus); 3// ['search_pages', 'search_filter'], ['search_pages', 'search_filter'] 4 5console.log(JSON.stringify(a_key) === JSON.stringify(b_key));

これでは一番上の階層しか比較できないので
下改装まで比較する必要があります

投稿2021/02/13 12:16

DaiGuard

総合スコア159

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kata2murin

2021/02/13 12:27

ご回答ありがとうございます。「試したこと」にある check_same_keys() がそれにあたると思うのですが…
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問