如何使用 DBXJSON 将带有转义/特殊字符的字符串与 JSON 相互转换?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11785963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I convert a string to and from JSON with escaped/special characters using DBXJSON?
提问by Doug
I'm having trouble converting a string with escaped characters toand froma TJsonString. (I'm using Delphi XE 2, Update 4, Hotfix 1).
我无法用转义字符转换为字符串,以和从一个TJsonString。(我使用的是 Delphi XE 2、Update 4、Hotfix 1)。
NOTE: I am familiar with the SuperObject, but my requirements are to use the DBXJSON unit.
注意:我熟悉SuperObject,但我的要求是使用 DBXJSON 单元。
It looks like the TJSONString is not correctly escaped when returning the JSON representation via the ToString() method.
通过 ToString() 方法返回 JSON 表示时,似乎 TJSONString 没有正确转义。
What (if anything) am I doing wrong and how do I correctly convert a string with special characters to/from its correct JSON representation?
我做错了什么(如果有的话),如何正确地将带有特殊字符的字符串转换为正确的 JSON 表示?
Perhaps I missed something, but none of the following Q&As seemed to address this directly:
也许我错过了一些东西,但以下问答似乎都没有直接解决这个问题:
- Delphi decode json/utf8 escaped text
- Delphi JSON library for XE2 available for object serialization
- Delphi: JSON array
- How to parse nested JSON object in Delphi XE2?
- Nested json object deserializing using Delphi 2012
- Delphi解码json/utf8转义文本
- XE2 的 Delphi JSON 库可用于对象序列化
- Delphi:JSON 数组
- 如何在 Delphi XE2 中解析嵌套的 JSON 对象?
- 使用 Delphi 2012 反序列化嵌套的 json 对象
EDIT:
As it turns out, the examples below were indeed working as expected.
What wasn't clear to me was that when creatinga TJSONString via it's constructor and adding it to a TJSONObject, the ToString() method will return an escapedrepresentation. However, after parsinga TJSONObject, the ToString() method will returned the un-escapedrepresentation.
The only other caveat was that the EscapeString() function in the sample code below was handling the double-quote. Although I wasn't using the double quote here, some of my other code was, and that caused the parsing to fail because TJSONString already escapes that character. I've updated my sample code to remove this handling from the EscapeString() function, which is what I've been using in my own classes.
Thanks again to @Linas for the answer, which helped me to "get" it.
编辑:
事实证明,下面的示例确实按预期工作。
我不清楚的是,当通过它的构造函数创建TJSONString 并将其添加到 TJSONObject 时,ToString() 方法将返回转义表示。但是,在解析TJSONObject 之后,ToString() 方法将返回未转义的表示形式。
唯一的其他警告是下面示例代码中的 EscapeString() 函数正在处理双引号。虽然我没有在这里使用双引号,但我的其他一些代码使用了,这导致解析失败,因为 TJSONString 已经转义了该字符。我已经更新了我的示例代码以从 EscapeString() 函数中删除这种处理,这是我在自己的类中使用的。
再次感谢@Linas 的回答,这帮助我“得到”了它。
Raw String Value:
原始字符串值:
Text := 'c:\path\name' +#13 + #10 + 'Next Line';
Text: c:\path\name
Next Line
What DBXJSON produces (NO ESCAPES):
DBXJSON 产生什么(没有转义):
JsonString: "c:\path\name
Next Line"
JsonPair: "MyString":"c:\path\name
Next Line"
JsonObject: {"MyString":"c:\path\name
Next Line"}
Parsing UN-escaped Text FAILS:
解析未转义的文本失败:
Text to parse: {"MyString":"c:\path\name
Next Line"}
Parsed JsonObject = *NIL*
What I EXPECTDBXJSON to produce:
我的处置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"}
Parsing ESCAPED Text (INVALID) (Text to parse validated with JSONLint):
解析 ESCAPED 文本(无效)(使用JSONLint进行解析验证的文本):
Text to parse: {"MyString":"c:\path\name\r\nNext Line"}
Parsed JsonObject.ToString(): {"MyString":"c:\path\name
Next Line"}
I've noticed that the only special character TJSONString seems to process correctly is the double quote (").
我注意到 TJSONString 似乎可以正确处理的唯一特殊字符是双引号 (")。
Here is the code I'm using:
这是我正在使用的代码:
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.
采纳答案by Linas
You can try to define your own TJSONString type and escape json strings there. E.g.:
您可以尝试定义自己的 TJSONString 类型并在那里转义 json 字符串。例如:
uses
DBXJSON;
type
TSvJsonString = class(TJSONString)
private
function EscapeValue(const AValue: string): string;
public
constructor Create(const AValue: string); overload;
end;
{ TSvJsonString }
constructor TSvJsonString.Create(const AValue: string);
begin
inherited Create(EscapeValue(AValue));
end;
function TSvJsonString.EscapeValue(const AValue: string): string;
procedure AddChars(const AChars: string; var Dest: string; var AIndex: Integer); inline;
begin
System.Insert(AChars, Dest, AIndex);
System.Delete(Dest, AIndex + 2, 1);
Inc(AIndex, 2);
end;
procedure AddUnicodeChars(const AChars: string; var Dest: string; var AIndex: Integer); inline;
begin
System.Insert(AChars, Dest, AIndex);
System.Delete(Dest, AIndex + 6, 1);
Inc(AIndex, 6);
end;
var
i, ix: Integer;
AChar: Char;
begin
Result := AValue;
ix := 1;
for i := 1 to System.Length(AValue) do
begin
AChar := AValue[i];
case AChar of
'/', '\', '"':
begin
System.Insert('\', Result, ix);
Inc(ix, 2);
end;
#8: //backspace \b
begin
AddChars('\b', Result, ix);
end;
#9:
begin
AddChars('\t', Result, ix);
end;
#10:
begin
AddChars('\n', Result, ix);
end;
#12:
begin
AddChars('\f', Result, ix);
end;
#13:
begin
AddChars('\r', Result, ix);
end;
#0 .. #7, #11, #14 .. #31:
begin
AddUnicodeChars('\u' + IntToHex(Word(AChar), 4), Result, ix);
end
else
begin
if Word(AChar) > 127 then
begin
AddUnicodeChars('\u' + IntToHex(Word(AChar), 4), Result, ix);
end
else
begin
Inc(ix);
end;
end;
end;
end;
end;
Usage example:
用法示例:
procedure Test;
var
LText, LEscapedText: string;
LJsonString: TSvJsonString;
LJsonPair: TJsonPair;
LJsonObject: TJsonObject;
begin
LText := 'c:\path\name' + #13 + #10 + 'Next Line';
LJsonString := TSvJsonString.Create(LText);
LJsonPair := TJsonPair.Create('MyString', LJsonString);
LJsonObject := TJsonObject.Create(LJsonPair);
try
LEscapedText := LJsonObject.ToString;
//LEscapedText is: c:\path\name\r\nNext Line
finally
LJsonObject.Free;
end;
end;
And this is how parsing should be done:
这就是应该如何进行解析:
//AText := '{"MyString":"c:\path\name\r\nNext Line"}';
function Parse(const AText: string): string;
var
obj: TJSONValue;
begin
obj := TJSONObject.ParseJSONValue(AText);
try
Result := obj.ToString;
//Result := {"MyString":"c:\path\name
//Next Line"}
finally
obj.Free;
end;
end;
回答by NightCabbage
We just ran into this lovely problem, where our backslashes weren't being escaped (but our double quotes were, apparently lol)...
我们刚刚遇到了这个可爱的问题,我们的反斜杠没有被转义(但我们的双引号显然是,哈哈)......
The solution was to stop using TJSONObject.ToString(), and use TJSONObject.ToJSON()instead. This gives you the correctly escaped string, as opposed to the human readable format that ToString()returns.
解决方案是停止使用TJSONObject.ToString(),TJSONObject.ToJSON()而是使用。这为您提供了正确转义的字符串,而不是返回的人类可读格式ToString()。
Hope this helps someone :)
希望这对某人有所帮助:)

