如何在JavaScript中完全获取具有重复键的JSON

6

我尝试从URL获取JSON,但在响应对象中,重复的键被移除了。有没有办法完整地获取它而不删除重复的键?下面是我的JavaScript代码:

$('document').ready(function(){
    var s = $.getJSON("new.json");
    console.log(s);
});

以下是我的new.json文件:
{
"s": "wae",
"s": "asd"
}

但是在控制台中,我得到的JSON对象如下:
responseJSON: Object
s: "asd"

提前感谢您


4
唯一的方法是手动解析JSON(即将JSON作为正常文本获取)。 - Prisoner
确实。你将不得不从头开始编写一个自定义的JSON解析器(除非有人已经发布了一个,但我不知道任何例子,而且这里的库推荐是不相关的)。这可能对于Stackoverflow来说是一个太广泛的主题。 - Quentin
5个回答

3

如果无法更改服务器响应,在处理简单的JSON数据时,可以像文本一样请求JSON并将其解析为字符串:

var check = new RegExp('["\']([^\'"]*)[\'"][^:]*:[^"\']*["\']([^\'"]*)[\'"]',"g");
    $.ajax({
        url : "text.json",
        dataType : "text",
        success : function(data){
            var newData = {};
            data.replace(check,function(a,b,c){
                if(typeof newData[b] == "undefined"){
                    newData[b] = c;
                }else if(typeof newData[b] == "object"){
                    newData[b].push(c);
                }else{
                    var ca = newData[b];
                    newData[b] = [ca,c];                     
                }
                return a;
            });
            console.log(newData);
            console.log($.parseJSON(data));
        },
        error : function(e,a){
            console.log(e,a);
        }
    });

在这段代码中,newData代表您的JSON数据:
{"s": ["wae","asd"]}

1
这不可能使用JSON.parse()实现。我相信更现代的ES规范说明后续的键会覆盖先前的键。
然而,JSON规范并没有禁止这样的JSON。而且有一些替代解析器和序列化程序可以在JavaScript内部生成和使用这样的JSON。例如,您可以使用SAX风格的JSON解析器clarinet
const clarinet = require('clarinet');

const parser = clarinet.parser();
const result = [];
parser.onkey = parser.onopenobject = k => {
    result.push({key: k, value: null});
};
parser.onvalue = v => {
    result[result.length - 1].value = v;
};
parser.write('{"a": "1", "a": "2"}').close();

console.log(result);
// [ { key: 'a', value: '1' }, { key: 'a', value: '2' } ]

如果您想知道如何在浏览器中使用 require(),请学习如何使用 webpack

1

JSON对象中的键应该是唯一的。否则,在请求该键时,通常会显示具有该值的最后一个键。如果键相同,也会更难区分对象的属性。键的整个目的是使其可访问和可用。

为了解决这个问题,您可以采取以下方法:

  1. 更改JSON中的键

  2. 将JSON更改为包含数组

    {"s": ["wae","asd"]}

JavaScript对象表示法(JSON)数据交换格式(RFC7159)中指出:

对象中的名称应该是唯一的。

在这个上下文中,应该的含义必须理解为在RFC 2119中指定的。

SHOULD(推荐)这个词,或者形容词“建议”,意味着在特定情况下可能存在合理的理由忽略某个特定项目,但在选择不同方案之前必须了解并仔细权衡全部影响。


RFC 7159解释了为什么唯一键很好: 一个对象的所有名称都是唯一的,这个对象在互操作方面是相互兼容的,因为接收该对象的所有软件实现都将同意名称-值映射。当对象内的名称不唯一时,接收这样的对象的软件行为是不可预测的。许多实现仅报告最后一个名称/值对。其他实现报告错误或无法解析该对象,并且一些实现报告所有名称/值对,包括重复项。 观察到JSON解析库在是否使对象成员的排序对调用软件可见方面存在差异。行为不依赖于成员排序的实现将在互操作方面是相互兼容的,因为它们不会受到这些差异的影响。

11
虽然这些建议都很好,但实际上并没有回答问题。 - Quentin
@Quentin 是的,但从示例中看来,他似乎能够自己更改JSON,而且我觉得与其试图回答问题,不妨尝试提供一些良好实践的想法,以便实现解决方法。上面的答案对于评论来说也相当长,并且会受到格式不足的影响。 - Craicerjack
我只是给了一个示例。实际上,我无法更改JSON。我想知道是否有可能获取没有重复项的数据。根据评论来看,似乎不可能。 - Saju
1
@Quentin,@Craicerjack 谢谢你们。 - Saju

1

JSON允许重复的键,但Javascript 对象不允许。

由于键可以重复,这意味着JSON无法表示为基于键/值的字典,并且不能直接转换为Javascript 对象

您将需要“遍历”JSON中的每个键/值对,然后根据需要进行处理。我不知道您要转换成什么结构,但只要它不是Javascript 对象,那就没问题。例如,您可能会遍历JSON对象并将值输出到一个可以重复“键”的.ini.css文件中。

JSON.parse()将不起作用,因为它会尝试解析为Javascript 对象,而该对象不允许重复的键。解决方法是如果键被重用,则简单地覆盖任何先前的值。但是,我们可以使用基于JSON.parse()工作原理的代码,而不是在Javascript 对象上设置属性,您可以从那里拆分并应用自定义解决方案。

你可以修改像 json2 这样的完整JSON解析器,或者使用像 clarinetOboe.js 这样的流式键解析器。

0

您可以尝试使用给定的结构来多次使用相同的键:

[
  {"s": "wae"},
  {"s": "asd"}
]

正如Craicerjack所建议的那样,您也可以选择使用数组来存储单个键的多个值:

{"s": ["wae","asd"]}

谢谢Arvind。但我的问题是,是否可以在不更改JSON的情况下实现? - Saju

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接