解析没有逗号分隔符的JSON数据

9

我的JSON如下:

{"_id":707860,"name":"Hurzuf","country":"UA","coord":{"lon":34.283333,"lat":44.549999}}
{"_id":519188,"name":"Novinki","country":"RU","coord":{"lon":37.666668,"lat":55.683334}}
{"_id":1283378,"name":"Gorkhā","country":"NP","coord":{"lon":84.633331,"lat":28}}
{"_id":1270260,"name":"State of Haryāna","country":"IN","coord":{"lon":76,"lat":29}}
{"_id":708546,"name":"Holubynka","country":"UA","coord":{"lon":33.900002,"lat":44.599998}}

这是一个没有逗号分隔符的JSON文件,如何读取它?我尝试解析JSON并在其中添加逗号,但也无法做到。

myapp.controller('Ctrl', ['$scope', '$http', function($scope, $http) {
  $http.get('todos.json').success(function(data) {
    var nuarr = data.toString().split("\n");
    for(i in nuarr) {
      myjson.push(i+",");
    }
  });
}]);

那根本不是JSON。 - Phil
你能按照自己的意愿更改JSON吗?如果可以,请用"["和"]"(不带引号)将数据包装起来,并在每行末尾添加","(但最后一行除外)。 - s.xie
jq --slurp 将其转换为 JSON 数组。 - Brent Bradburn
9个回答

7

这种格式通常称为“换行分隔的JSON”或“ndjson”; 有几个模块可以解析它,但如果你的数据集很小并且可以一次性完成,那么你正在正确的道路上:

var ndjson = "..." // assuming your data is already loaded in as a string

var records = ndjson.split('\n').map(function (record) {
    return JSON.parse(record)
})

这样稍微简化了一下,但是你所有的记录都在一个数组中,作为解析后的JSON对象。之后你对它们做什么取决于你自己,但是这里的关键是你的JSON是一个对象列表,而不是单个对象:你不想将它作为整体解析,而是作为单独的记录进行解析。

那么,假设你想创建一个以各个ID为键的对象,那可能很有帮助:

var recordHash = {}

records.forEach(function (record) {
    recordHash[record._id] = record
})

现在你可以通过recordHash['12345678']来访问单个记录,假设12345678是你想要的记录id。你需要将记录变异为适合你的应用程序的任何数据结构,因此它真的取决于你正在寻找什么,但这个例子可能会让你有所启发。
我真的不建议在解析之前尝试将收到的数据变异为其他格式; 它很脆弱。你会发现,按照你提供的方式解析数据,然后将其转换为适合你的应用程序的任何数据结构,更安全、更可重复使用。

1
继续跟进 @milkandtang —— 既然您已经有了一个 ndjson 格式的文件,那么可以使用 Node.js 工具包 https://github.com/mbostock/ndjson-cli。尝试使用 ndjson-filterndjson-mapndjson-reduce - RobLabs
@RobLabs,我该如何将一个JSON文件传递给ndjson-filter? - Matt
@matt — 要传递一个JSON文件,请参见此处的示例:https://github.com/mbostock/ndjson-cli#ndjson_filter - RobLabs

2
$http.get 要求响应必须是 JSON 格式。您可以编写自己的自定义响应转换器来实现。
$http({
  url: 'todos.json',
  method: 'GET',
  transformResponse: function (data) {
      return data.split('\n').map(function(line) {
          return JSON.parse(line);
      });
  }
}).success(function (response) {
   console.log(response);
   // do whatever you want to do
   // response will be of type array of objects
});

你的第5-9行代码做的事情和map函数完全一样,只是表述方式更冗长。 - user663031

1
您的JSON需要是一个单一的对象或数组。仅用逗号将一堆对象拼接在一起并不能定义一个单一的JSON对象。尝试使用以下方法来获取可解析的对象数组:
var nuarr = data.toString().split("\n");
myjson = '[' + nuarr.join(',') + ']';

然后,JSON.parse(myjson) 应该返回一个对象数组。或者,您可以将 nuarr 的每个元素映射到其 JSON 解析值,并将结果收集到另一个数组中。

0

尽管看起来很愚蠢,但我们厌倦了在JSON中使用逗号和引号,以及没有注释或多行字符串。

知道Douglas Crockford和他的信徒会哭叫“亵渎”,我们继续编写了我们自己的Relaxed Json语法的规范、解析器和格式化程序。

事实上,你并不真正需要逗号,只有在极少数情况下才需要引号。你也不需要换行。

使用Relaxed Json,为了使你的示例工作,你只需在你已经拥有的内容周围放上'['和']',然后调用

val realJson = parser.stringToJson(...)

  • 但是,在数组值之间你不需要换行。

  • 你还可以删除键值之间所有的逗号。

  • 你不需要在键周围加上引号。

所以你可以这样做:

[ 
  { _id:707860 name:Hurzuf country:UA
    coord:{lon:34.283333 lat:44.549999}
  }
  { _id:519188 name:Novinki country:RU 
    coord:{lon:37.666668 lat:55.683334}
  }
]

规范链接: http://www.relaxedjson.org

NPM链接: https://www.npmjs.com/package/really-relaxed-json

将示例粘贴到此处以查看解析的简易性: http://www.relaxedjson.org/docs/converter.html


0
var myJson = nuarr.join(',');

但你真正想做什么呢?你的代码将带有逗号的字符串推入数组中,因此最终得到

["{...},", "{...},", ...]


0

我认为您拥有一组JSON对象,分隔符为换行符。

尝试这个:

myapp.controller('Ctrl', ['$scope', '$http', function($scope, $http) {

  $http.get('todos.json').success(function(data) {

   myjson = data.split("\n").map(function(line) { return JSON.parse(line); });

  });

}]);

0
$http.get期望响应是json格式的。你可以编写自定义的响应转换器来实现这一点。
$http({
  url: 'todos.json',
  method: 'GET',
  transformResponse: function (data) {
      return data.split('\n').map(function(line) {
          return JSON.parse(line);
      });
  }
}).success(function (response) {
   console.log(response);
   // do whatever you want to do
   // response will be of type array of objects
});

0

更新 2022

@milkandtang 的回答让我找到了正确的方向,但是 JSON.parse() 在拆分行后仍然给我带来了麻烦并返回错误。它一直抱怨行为空或格式不正确。

这是适用于新行分隔 JSON 的解决方法。

var ndjson = data;//must be a string

//declare variable that will be array of json
var json = []; 

//split
ndjson.split('\n').map(function (record) {

//regex to format each array to a json object
var array = JSON.parse(`[${record.replace(/\}\n\{/g, '},{')}]`);

//push to json array
json.push(array);

})

//pheeew...
console.log(json);

0
使用正则表达式将文本拆分成行,然后将每一行映射为其JSON解析后的等效对象,从而生成每行对象的数组:
input . match(/^.*$/gm) . map(JSON.parse)

或者像其他答案建议的那样使用split

input . split('\n') . map(JSON.parse)

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