我正在尝试解析从REST Web服务返回的一些JSON。 get()调用的返回值是TStringStream。我正在使用dbxjson来处理数据。为了让事情更容易在这里展示,我创建了再现错误,而不调用Web服务(使用web服务的输出,而不是一个文本文件)一个测试项目。这是代码:
var SL : TStringStream;
LJsonObj : TJSONObject;
begin
SL := TStringStream.Create;
try
SL.LoadFromFile('output.txt');
LJsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(SL.DataString), 0) as TJSONObject;
finally
SL.Free;
end;
end;
有时此JSON数据中的phone_numbers数组为空。在来自Web服务调用的流对象中,它看起来像这样:
{
"Contact Information Service": {
"response": {
"phone_numbers": [
]
}
}
}
这会导致ParseJSONValue返回nil值。
但是,如果我在我的测试txt文件中将空的phone_numbers数组更改为:
{
"Contact Information Service": {
"response": {
"phone_numbers": []
}
}
}
它工作正常(即返回TJSONObject)。不同之处在于空数组中的空格。由于某种原因,空数组中具有空格的第一个JSON响应导致ParseJSONValue返回nil。它工作正常,方括号之间没有空格。
我的JSON解析出错了什么?在调用ParseJSONValue之前是否需要进行某种预解析?
答案 0 :(得分:10)
这个问题并不包括Delphi JSON实现(DBXJSON),我使用了一些具有相同限制的JSON PHP解析器。
现在因为JSON解析器忽略了(并且必须)忽略双引号字符串文字之外的所有空格,所以可以安全地删除这些空格,因此可能的解决方法是 Minify 你的Json字符串,然后再解析它。
尝试此示例,该示例使用正则表达式从字符串中删除多余的空格。
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.RegularExpressions,
System.Classes,
System.SysUtils,
Data.DBXJSON;
const
JsonString=
'{'+
' "Contact Information Service": {'+
' "response": {'+
' "phone_numbers": [ ]'+
' }'+
' }'+
'}';
function JsonMinify(const S: string): string;
begin
Result:=TRegEx.Replace(S,'("(?:[^"\\]|\\.)*")|\s+', '$1');
end;
procedure TestJSon;
var
s : string;
SL : TStringStream;
LJsonObj : TJSONObject;
begin
SL := TStringStream.Create;
try
s:=JsonMinify(JsonString);
SL.WriteString(s);
LJsonObj := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(SL.DataString), 0) as TJSONObject;
Writeln(LJsonObj.Size);
finally
SL.Free;
end;
end;
begin
try
TestJSon;
except
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Press Enter to exit');
Readln;
end.
答案 1 :(得分:7)
看看TJsonObject.ParseArray
。你会发现这个:
while ValueExpected or (Br.PeekByte <> Ord(']')) do
begin
ConsumeWhitespaces(Br);
Pos := ParseValue(Br, JsonArray);
if Pos <= 0 then
Exit(Pos);
所以在数组的顶部(在它读取开括号之后),如果下一个字符不是一个紧括号,请吃空格然后尝试读取有效的JSON值。关闭括号不是有效的JSON值,因此此时它会失效。
这似乎是有效的JSON,(我可以让我的浏览器接受它作为一个有效的JavaScript对象),所以这应该被认为是DBXJSON库中的一个错误。您可能需要预先解析它,使用不同的JSON库(Delphi有一些)或找到一种方法来确保发送给您的信息不包含此模式。
无论哪种方式,您都应该将此报告给QC作为错误。