Как вы написали:
В текстах JSON не должно быть дубликатов ключей согласно RFC 7159
и, следовательно, дубликаты ключей будут заменены при синтаксическом анализе JSON на JSON.parse()
(что и делает JQuery за кулисами). Это означает, что вам нужно проверить дубликаты ключей перед этапом JSON-разбора.
У меня нет чистого решения, но в зависимости от ваших потребностей в валидации этого может быть достаточно:
Вы можете в основном использовать что-то вроде this , чтобы минимизировать ваши входящие данные JSON (из запроса) и сохранить их в переменной, затем вызвать JSON.parse()
для данных ответа, а также преобразовать в строку и минимизировать это. а затем сравнить два для равенства строк. Если они не равны, вы могли бы вычесть, что были дублирующиеся ключи, хотя не то, какие именно ключи ... но, как я уже сказал, если вы просто хотите выдать ошибку, если обнаружены дублирующие ключи любого типа, этого будет достаточно.
/*! JSON.minify()
v0.1 (c) Kyle Simpson
MIT License
*/
/**
* @name minify.json.js
* @author Kei Funagayama <kei.topaz@gmail.com
* @overview JSON.minify
*/
/**
* @namespace JSON
*/
(function(global){
'use strict';
/**
* @function
* @memberof JSON
* @param {Object} Transformed data. format) json-like
* @return {String}
*
* @example
* var json = { // hoge
* "foo": "bar",// this is cool
* "bar": [
* "baz", "bum", "zam" // this is cool
* ]
* } // hoge
*
*/
var minify = function (json) {
var tokenizer = /"|(\/\*)|(\*\/)|(\/\/)|\n|\r|\[|]/g,
in_string = false,
in_multiline_comment = false,
in_singleline_comment = false,
tmp, tmp2, new_str = [], ns = 0, from = 0, lc, rc
;
tokenizer.lastIndex = 0;
while ( tmp = tokenizer.exec(json) ) {
lc = RegExp.leftContext;
rc = RegExp.rightContext;
if (!in_multiline_comment && !in_singleline_comment) {
tmp2 = lc.substring(from);
if (!in_string) {
tmp2 = tmp2.replace(/(\n|\r|\s)*/g,"");
}
new_str[ns++] = tmp2;
}
from = tokenizer.lastIndex;
if (tmp[0] === "\"" && !in_multiline_comment && !in_singleline_comment) {
tmp2 = lc.match(/(\\)*$/);
if (!in_string || !tmp2 || (tmp2[0].length % 2) === 0) { // start of string with ", or unescaped " character found to end string
in_string = !in_string;
}
from--; // include " character in next catch
rc = json.substring(from);
}
else if (tmp[0] === "/*" && !in_string && !in_multiline_comment && !in_singleline_comment) {
in_multiline_comment = true;
}
else if (tmp[0] === "*/" && !in_string && in_multiline_comment && !in_singleline_comment) {
in_multiline_comment = false;
}
else if (tmp[0] === "//" && !in_string && !in_multiline_comment && !in_singleline_comment) {
in_singleline_comment = true;
}
else if ((tmp[0] === "\n" || tmp[0] === "\r") && !in_string && !in_multiline_comment && in_singleline_comment) {
in_singleline_comment = false;
}
else if (!in_multiline_comment && !in_singleline_comment && !(/\n|\r|\s/.test(tmp[0]))) {
new_str[ns++] = tmp[0];
}
}
new_str[ns++] = rc;
return new_str.join("");
};
if (typeof module !== 'undefined' && module.exports) {
// node
module.exports = minify;
JSON.minify = minify;
} else {
// others, export global
if (typeof global.JSON === "undefined" || !global.JSON) {
global.JSON = {};
}
global.JSON.minify = minify;
}
})(this);
$.ajax({
url: 'https://jsonplaceholder.typicode.com/users',
// make sure jQuery doesn't try to be smart and parse the JSON already
dataType: 'text'
}).done(function(data) {
var raw = JSON.minify(data);
var parsed = JSON.minify(JSON.stringify(JSON.parse(data)));
if ( raw === parsed ) {
console.log('No duplicate keys found');
} else {
console.log('Possible duplicate keys!');
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Если вам действительно нужно пойти дальше и выяснить, какой ключ является дубликатом, вы можете запустить какой-нибудь метод string-diff, чтобы найти разницу между raw
и parsed
и продолжить оттуда.