У меня возникли проблемы с преобразованием строки с экранированными символами в и из TJsonString. (Я использую Delphi XE 2, обновление 4, исправление 1).
ПРИМЕЧАНИЕ. Я знаком с SuperObject, но мои требования состоят в том, чтобы использовать блок DBXJSON.
Похоже, что TJSONString неправильно экранируется при возврате представления JSON с помощью метода ToString().
Что (если что-нибудь) Я делаю неправильно и как правильно преобразовать строку со специальными символами в/из ее правильного представления JSON?
Возможно, я что-то пропустил, но ни один из следующих вопросов Q & As, как представляется, прямо не затрагивал:
- Delphi decode json/utf8 экранированный текст
- Библиотека Delphi JSON для XE2, доступная для сериализации объектов
- Delphi: массив JSON
- Как разобрать вложенный объект JSON в Delphi XE2?
- десериализация вложенных дескрипторов json с использованием Delphi 2012
EDIT:
Как оказалось, приведенные ниже примеры действительно работали, как ожидалось.
Мне было непонятно, что при создании TJSONString через конструктор и добавлении его в TJSONObject метод ToString() возвращает представление escaped, Однако после анализа TJSONObject метод ToString() вернет представление неэкранированное.
Единственное другое предостережение заключалось в том, что функция EscapeString() в приведенном ниже примере кода обрабатывала двойную кавычку. Хотя я не использовал двойную кавычку здесь, некоторые из моих других кодов были, и это вызвало синтаксический разбор, потому что TJSONString уже ускользает от этого символа. Я обновил свой пример кода, чтобы удалить эту обработку из функции EscapeString(), что я и использовал в своих классах.
Еще раз спасибо @Linas за ответ, который помог мне "получить" его.
Значение Raw String:
Text := 'c:\path\name' +#13 + #10 + 'Next Line';
Text: c:\path\name
Next Line
Что производит DBXJSON (без ESCAPES):
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*
Что я EXDECT 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"}
Разбор текста ESCAPED (INVALID) (текст для проверки с помощью 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.