Delphi JSON空数组
我试图解析从RESTWeb服务返回的一些JSON。get()调用返回的是TStringStream。我使用dbxjson处理数据。为了更容易在这里演示,我创建了一个测试项目,它在不调用web服务的情况下复制错误(使用文本文件作为web服务输出)。代码如下:Delphi JSON空数组,delphi,delphi-xe2,Delphi,Delphi Xe2,我试图解析从RESTWeb服务返回的一些JSON。get()调用返回的是TStringStream。我使用dbxjson处理数据。为了更容易在这里演示,我创建了一个测试项目,它在不调用web服务的情况下复制错误(使用文本文件作为web服务输出)。代码如下: var SL : TStringStream; LJsonObj : TJSONObject; begin SL := TStringStream.Create; try SL.LoadFromFile('output.t
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数据中的电话号码数组为空。在来自web服务调用的流对象中,它如下所示:
{
"Contact Information Service": {
"response": {
"phone_numbers": [
]
}
}
}
这将导致ParseJSONValue返回一个nil值
但是,如果我在测试txt文件中将空电话号码数组更改为:
{
"Contact Information Service": {
"response": {
"phone_numbers": []
}
}
}
它工作正常(即返回TJSONObject)。区别在于空数组中的空格。出于某种原因,第一个JSON响应在空数组中带有空格,导致ParseJSONValue返回nil。它工作正常,方括号之间没有空格
我的JSON解析有什么错?在调用ParseJSONValue之前,我需要进行某种预解析吗?看看
TJsonObject.ParseArray
。你会发现:
while ValueExpected or (Br.PeekByte <> Ord(']')) do
begin
ConsumeWhitespaces(Br);
Pos := ParseValue(Br, JsonArray);
if Pos <= 0 then
Exit(Pos);
whilevalueexpected或(Br.peek字节Ord(']')do
开始
用户空白(Br);
Pos:=解析值(Br,JsonArray);
如果Pos这个问题不是Delphi JSON实现(DBXJSON)所独有的,那么我使用的一些JSON PHP解析器也有同样的限制
现在,由于JSON解析器会(并且必须)忽略双引号字符串文本之外的所有空格,因此可以安全地删除这些空格,因此一种可能的解决方法是在解析JSON字符串之前缩小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.
看起来这很可能是TJSONByteReader实现中的一个bug,但坦率地说,试图弄清楚解析代码的意义使我们无法一目了然。从经验上看,证据相当清楚。幸运的是,我自己的TJSONObject阅读器可以很好地处理此类情况。该发表了吗?:)@德尔蒂斯:真的吗?我在研究这个问题的过程中进行了跟踪,我发现理解解析代码并没有那么困难。我认为解析器写得很糟糕——如果它有一个合适的词法分析器,而不是将词法分析与解析混合在一起,那么这个问题就完全可以避免——但要理解发生了什么并不难……如果你发现PeekByte()很容易理解,那么你就必须用十六进制作梦。:)当我发布我的JSON代码时,你会看到我认为可读的(我敢说可维护的)代码和UM,dxxJSON之间的区别。因为我没有解决我正在经历的问题,所以当我遇到PekByTee()时,我放弃了,作为一个明确的“这里是龙”的红旗。所以我从来没有真正了解过ParseArray(),正如您在下面提到的,它非常清楚,而且明显有缺陷。(Parse..()方法在TJSONObject中到底在做什么?)@Deltics:你的意思是你不会做梦?我想我已经习惯了。我甚至看不到代码了。我只看到金发、黑发、红发……;)但是,即使正确实现JSON规范(您已经在XE2中购买了该功能)是一个明显而简单的失败,您也无法在XE2中修复它。你忘了提那部分。