我在将一个包含转义字符的字符串转换为和从 TJsonString 转换时遇到了问题。(我使用的是 Delphi XE 2,Update 4,Hotfix 1)。
注意:我熟悉 SuperObject,但我的要求是使用 DBXJSON 单元。
看起来 TJSONString 在通过 ToString() 方法返回 JSON 表示形式时未正确转义。 我做错了什么(如果有的话),如何正确地将带有特殊字符的字符串转换为其正确的 JSON 表示形式? 也许我漏掉了什么,但以下任何一个 Q&A 都似乎没有直接解决这个问题:
注意:我熟悉 SuperObject,但我的要求是使用 DBXJSON 单元。
看起来 TJSONString 在通过 ToString() 方法返回 JSON 表示形式时未正确转义。 我做错了什么(如果有的话),如何正确地将带有特殊字符的字符串转换为其正确的 JSON 表示形式? 也许我漏掉了什么,但以下任何一个 Q&A 都似乎没有直接解决这个问题:
- Delphi 解码 json/utf8 转义文本
- Delphi XE2 可用于对象序列化的 JSON 库
- Delphi: JSON 数组
- 如何在 Delphi XE2 中解析嵌套的 JSON 对象?
- 使用 Delphi 2012 进行嵌套 json 对象反序列化
原始字符串值:编辑:
事实证明,下面的示例确实按预期工作。
对我不清楚的是,当通过它的构造函数创建一个 TJSONString 并将其添加到 TJSONObject 中时,ToString() 方法将返回一个转义的表示形式。但是,在解析 TJSONObject 后,ToString() 方法将返回未转义的表示形式。
唯一的其他注意事项是,样本代码中的 EscapeString() 函数正在处理双引号。虽然我在这里没有使用双引号,但我的其他一些代码使用了双引号,这导致解析失败,因为 TJSONString 已经转义了该字符。我已更新示例代码,从 EscapeString() 函数中删除此处理,这是我在自己的类中使用的。
再次感谢 @Linas 的答案,帮助我“get”到了它。
Text := 'c:\path\name' +#13 + #10 + 'Next Line';
Text: c:\path\name
Next Line
DBXJSON 的输出结果(无需转义):
JsonString: "c:\path\name
Next Line"
JsonPair: "MyString":"c:\path\name
Next Line"
JsonObject: {"MyString":"c:\path\name
Next Line"}
解析未转义的文本失败:
Text to parse: {"MyString":"c:\path\name
Next Line"}
Parsed JsonObject = *NIL*
我希望DBXJSON能够产生以下结果:
Escaped String: c:\\path\\name\r\nNext Line
JsonString: "c:\\path\\name\r\nNext Line"
JsonPair: "MyString":"c:\\path\\name\r\nNext Line"
JsonObject: {"MyString":"c:\\path\\name\r\nNext Line"}
解析转义文本(无效)(使用JSONLint验证的待解析文本):
Text to parse: {"MyString":"c:\\path\\name\r\nNext Line"}
Parsed JsonObject.ToString(): {"MyString":"c:\path\name
Next Line"}
我注意到TJSONString只能正确处理双引号(")这个特殊字符。
这是我正在使用的代码:
program JsonTest;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, DbxJson;
function EscapeString(const AValue: string): string;
const
ESCAPE = '\';
// QUOTATION_MARK = '"';
REVERSE_SOLIDUS = '\';
SOLIDUS = '/';
BACKSPACE = #8;
FORM_FEED = #12;
NEW_LINE = #10;
CARRIAGE_RETURN = #13;
HORIZONTAL_TAB = #9;
var
AChar: Char;
begin
Result := '';
for AChar in AValue do
begin
case AChar of
// !! Double quote (") is handled by TJSONString
// QUOTATION_MARK: Result := Result + ESCAPE + QUOTATION_MARK;
REVERSE_SOLIDUS: Result := Result + ESCAPE + REVERSE_SOLIDUS;
SOLIDUS: Result := Result + ESCAPE + SOLIDUS;
BACKSPACE: Result := Result + ESCAPE + 'b';
FORM_FEED: Result := Result + ESCAPE + 'f';
NEW_LINE: Result := Result + ESCAPE + 'n';
CARRIAGE_RETURN: Result := Result + ESCAPE + 'r';
HORIZONTAL_TAB: Result := Result + ESCAPE + 't';
else
begin
if (Integer(AChar) < 32) or (Integer(AChar) > 126) then
Result := Result + ESCAPE + 'u' + IntToHex(Integer(AChar), 4)
else
Result := Result + AChar;
end;
end;
end;
end;
procedure Test;
var
Text: string;
JsonString: TJsonString;
JsonPair: TJsonPair;
JsonObject: TJsonObject;
begin
try
Writeln('Raw String Value');
Writeln('-----------------');
Text := 'c:\path\name' +#13 + #10 + 'Next Line';
Writeln('Text: ', Text);
JsonString := TJsonString.Create(Text);
JsonPair := TJsonPair.Create('MyString', JsonString);
JsonObject := TJsonObject.Create(JsonPair);
// DBXJSON results
Writeln;
Writeln('What DBXJSON produces');
Writeln('---------------------');
Writeln('JsonString: ', JsonString.ToString);
Writeln;
Writeln('JsonPair: ', JsonPair.ToString);
Writeln;
Writeln('JsonObject: ', JsonObject.ToString);
Writeln;
// assign JSON representation
Text := JsonObject.ToString;
// free json object
JsonObject.Free;
// parse it
JsonObject:= TJsonObject.ParseJsonValue(TEncoding.ASCII.GetBytes(
Text), 0) as TJsonObject;
Writeln('Parsing UN-escaped Text *FAILS* ');
Writeln('----------------------------------');
Writeln('Text to parse: ', Text);
Writeln;
if (JsonObject = nil) then
Writeln('Parsed JsonObject = *NIL*')
else
Writeln('Parsed JsonObject: ', JsonObject.ToString);
Writeln;
// free json object
JsonObject.Free;
// expected results
Text := 'c:\path\name' +#13 + #10 + 'Next Line';
Text := EscapeString(Text);
JsonString := TJsonString.Create(Text);
JsonPair := TJsonPair.Create('MyString', JsonString);
JsonObject := TJsonObject.Create(JsonPair);
Writeln('What I *EXPECT* DBXJSON to produce');
Writeln('----------------------------------');
Writeln('Escaped String: ', Text);
Writeln;
Writeln('JsonString: ', JsonString.ToString);
Writeln;
Writeln('JsonPair: ', JsonPair.ToString);
Writeln;
Writeln('JsonObject: ', JsonObject.ToString);
Writeln;
// assign JSON representation
Text := JsonObject.ToString;
// free json object
JsonObject.Free;
// parse it
JsonObject:= TJsonObject.ParseJsonValue(TEncoding.ASCII.GetBytes(
Text), 0) as TJsonObject;
Writeln('Parsing ESCAPED Text (*INVALID*) ');
Writeln('----------------------------------');
Writeln('Text to parse: ', Text);
Writeln;
Writeln('Parsed JsonObject.ToString(): ', JsonObject.ToString);
Writeln;
Readln;
except
on E: Exception do
begin
Writeln(E.ClassName, ': ', E.Message);
Readln;
end;
end;
end;
begin
Test;
end.