是 jsonlint 不可靠,还是其他原因?
jsonlint可靠,ruby解析你发的json也没有问题:
require 'json'
require 'pp'
json = <<END_OF_JSON
{
"1": [
{
"title": "TITLE1",
"capital": "Rome",
"length": 2.7,
"date": "2017-1-2",
"tags": [
"Culture"
]
}],
"2": [
{
"title": "TITLE2",
"capital": "Paris",
"age": 1.2,
"date": "2017-2-1",
"tags": [
"Culture"
]
}]
}
END_OF_JSON
obj = JSON.parse(json)
pp obj
--output:--
{"1"=>
[{"title"=>"TITLE1",
"capital"=>"Rome",
"length"=>2.7,
"date"=>"2017-1-2",
"tags"=>["Culture"]}],
"2"=>
[{"title"=>"TITLE2",
"capital"=>"Paris",
"age"=>1.2,
"date"=>"2017-2-1",
"tags"=>["Culture"]}]}
但是,如果您查看文件或输出字符串,非打印字符不一定是可见的:
test = "\001hello"
puts test
p test
--output:--
hello
"\u0001hello"
你会在这里得到一个解析错误:
require 'json'
require 'pp'
json = <<END_OF_JSON
{
\001"1": [1, 2, 3]
}
END_OF_JSON
obj = JSON.parse(json)
即使输出时 json 看起来不错:
require 'json'
require 'pp'
json = <<END_OF_JSON
{
\001"1": [1, 2, 3]
}
END_OF_JSON
puts json
obj = JSON.parse(json)
--output:--
{
"1": [1, 2, 3]
}
/Users/7stud/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/json/common.rb:156:in `parse': 784: unexpected token at '{ (JSON::ParserError)
"1": [1, 2, 3]
}
'
from /Users/7stud/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/json/common.rb:156:in `parse'
from 1.rb:11:in `<main>'
因此您可能希望从文件中读取 json,然后使用 p 输出文本,然后检查文本中是否有任何奇怪的字符。
另外,请复制并粘贴您的完整错误消息 - 永远不要输入您认为错误消息所说的内容,然后声称这是您的程序产生的。我可以复制您使用此 json 发布的错误消息:
json = <<END_OF_JSON
(code) = {
"1": [
{
"title": "TITLE1",
"capital": "Rome",
"length": 2.7,
"date": "2017-1-2",
"tags": [
"Culture"
]
}],
"2": [
{
"title": "TITLE2",
"capital": "Paris",
"age": 1.2,
"date": "2017-2-1",
"tags": [
"Culture"
]
}]
}
END_OF_JSON
obj = JSON.parse(json)
--output:--
`parse': 784: unexpected token at '(code) = { (JSON::ParserError)
"1": [
{
"title": "TITLE1",
"capital": "Rome",
"length": 2.7,
"date": "2017-1-2",
"tags": [
"Culture"
]
}],
"2": [
{
"title": "TITLE2",
"capital": "Paris",
"age": 1.2,
"date": "2017-2-1",
"tags": [
"Culture"
]
}]
}
'
from /Users/7stud/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/json/common.rb:156:in `parse'
from 1.rb:29:in `<main>'
对评论 1 的回应:
错误信息包含rails看到的json,这里是:
399: unexpected token at ' { #<===Opening brace, which starts a javascript object.
"title": "TITLE1",
"capital": "Rome",
"length": 2.7,
"date": "2017-1-2",
"tags": [
"Culture"
]
}], #<====First, a closing brace that ends the javascript object, followed by a closing bracket, ending what?
"2": [
{
"title": "TITLE2",
"capital": "Paris",
"age": 1.2,
"date": "2017-2-1",
"tags": [
"Culture"
]
}]
}
如果我将无效的 json 放在 rails 视图中:
<%
json = <<END_OF_JSON
{
"title": "TITLE1",
"capital": "Rome",
"length": 2.7,
"date": "2017-1-2",
"tags": [
"Culture"
]
}],
"2": [
{
"title": "TITLE2",
"capital": "Paris",
"age": 1.2,
"date": "2017-2-1",
"tags": [
"Culture"
]
}]
}
END_OF_JSON
obj = JSON.parse(json)
%>
...然后在我的浏览器中输入将显示该视图的路线,这是我在浏览器中收到的错误消息:
Showing /Users/7stud/rails_projects/test4/app/views/users/index.html.erb where line #27 raised:
784: unexpected token at '{
"title": "TITLE1",
"capital": "Rome",
"length": 2.7,
"date": "2017-1-2",
"tags": [
"Culture"
]
}],
"2": [
{
"title": "TITLE2",
"capital": "Paris",
"age": 1.2,
"date": "2017-2-1",
"tags": [
"Culture"
]
}]
}
'
看起来很眼熟?相反,如果您在 json 的其他地方出现错误,例如这里:
<%
json = <<END_OF_JSON
{
"1": [
{
"title": "TITLE1",
"capital": "Rome",
"length": 2.7,
"date": "2017-1-2",
"tags": [
"Culture"
]
}
],
"2": #<====Missing opening bracket
{
"title": "TITLE2",
"capital": "Paris",
"age": 1.2,
"date": "2017-2-1",
"tags": [
"Culture"
]
}
]
}
END_OF_JSON
obj = JSON.parse(json)
%>
然后您会在浏览器中看到如下错误消息:
Showing /Users/7stud/rails_projects/test4/app/views/users/index.html.erb where line #32 raised:
784: unexpected token at '{
"1": [ #<===Note the presence of "1": [, unlike in your error message.
{
"title": "TITLE1",
"capital": "Rome",
"length": 2.7,
"date": "2017-1-2",
"tags": [
"Culture"
]
}
],
"2":
{
"title": "TITLE2",
"capital": "Paris",
"age": 1.2,
"date": "2017-2-1",
"tags": [
"Culture"
]
}
]
}
'
因此,"1": [ 不存在于 rails 看到的 json 中。如果您需要更多帮助,您需要复制并粘贴以下代码:
- 您的控制器和操作。
- 动作的视图。
对评论 2 的回应:
rails 视图能够无错误地呈现以下 json(删除所有空格):
<!--testing4.html.erb-->
<%
require 'json'
require 'pp'
json = <<END_OF_JSON
{
"1": [{"title": "TITLE1", "capital": "Rome", "length": 2.7, "date": "2017-1-2", "tags": ["Culture"]}],
"2": [{"title": "TITLE2", "capital": "Paris", "age": 1.2, "date": "2017-2-1", "tags": ["Culture"]}]
}
END_OF_JSON
%>
<%= obj = JSON.parse(json) %>
而且,rails 视图能够无错误地呈现以下 json(所有空白都添加回来):
<!--testing4.html.erb-->
<%
require 'json'
require 'pp'
json = <<END_OF_JSON
{
"1": [
{
"title": "TITLE1",
"capital": "Rome",
"length": 2.7,
"date": "2017-1-2",
"tags": [
"Culture"
]
}],
"2": [
{
"title": "TITLE2",
"capital": "Paris",
"age": 1.2, "date":
"2017-2-1",
"tags": [
"Culture"
]
}]
}
END_OF_JSON
%>
<%= obj = JSON.parse(json) %>
但是,由于某种原因,rails 视图无法呈现您的 json:
<!--testing4.html.erb-->
<%
require 'json'
require 'pp'
json = <<END_OF_JSON
{
"1": [
{
"title": "TITLE1",
"capital": "Rome",
"length": 2.7,
"date": "2017-1-2",
"tags": [
"Culture"
]
}],
"2": [
{
"title": "TITLE2",
"capital": "Paris",
"age": 1.2,
"date": "2017-2-1",
"tags": [
"Culture"
]
}]
}
END_OF_JSON
%>
<%= obj = JSON.parse(json) %>
经过进一步调查,您的 json 混合了 ascii 空格(十六进制表示法中的 20)和一种称为 EM SPACE 的 UTF-8 空格字符(UTF-8 中的U+2003、e2 80 83)。 json 中的第一个 EM SPACE 出现在此处:
{
"1": [
{
^
|
Right there
...巧合的是,rails 错误消息正在切断您的 json。在左大括号(十六进制表示法中的7b)之前是一个ascii空格(十六进制表示法中的20),而ascii空格前面的字符是一个三字节UTF-8字符,称为EM SPACE(U+2003 , e2 80 83 UTF-8)。以 UTF-8 编码编码的字符应该是合法的 json。 jsonlint 接受 EM SPACE,但 rails 对此感到窒息。
作为问题的一个简短示例,以下 javascript 数组在每个逗号后都有一个 EM SPACE:
<!--testing4.html.erb-->
<%
json = "[1, 2, 3]"
%>
<%= obj = JSON.parse(json) %>
这是我浏览器中的错误:
419: unexpected token at ' 2, 3]'
rails 错误将 json 截断到第一个 EM SPACE。
事实证明,虽然 json 中允许使用 UTF-8 字符,但 json 术语之间只允许使用少数 ascii 空白字符,而不仅仅是任何 UTF-8 字符。见RFC 7159。在 json 术语之间使用 EM SPACE 在概念上等同于在术语之间使用 z。因此,包含EM SPACE 字符的json 是非法的json。在字符串中使用EM SPACE 是合法的,但在 json 术语之间则不行。
以下 jsonlinter 报告带有 EM SPACE 字符的 json 无效:
http://www.freeformatter.com/json-validator.html
似乎有些 jsonlinter 比其他的更可靠。
解决方案:
您可以使用gsub() 将所有EM SPACE 字符替换为ascii 空格:
...
...
END_OF_JSON
clean_json = json.gsub("\u2003", ' ')
%>
<%= obj = JSON.parse(clean_json) %>
如果你从某处的服务中获得了那个 json,你应该给他们发一封电子邮件,让他们知道他们发送的 json 是非法的。