Tengo problemas para convertir una cadena con caracteres escapados a y de a TJsonString. (Estoy usando Delphi XE 2, Update 4, Hotfix 1).¿Cómo convierto una cadena hacia y desde JSON con caracteres escapados/especiales usando DBXJSON?
NOTA: Estoy familiarizado con el SuperObject, pero mis requisitos son utilizar la unidad DBXJSON.
Parece que TJSONString no se escapó correctamente al devolver la representación JSON mediante el método ToString().
¿Qué (si acaso) estoy haciendo mal y cómo convierto correctamente una cadena con caracteres especiales en/desde su representación correcta de JSON?
Tal vez me haya perdido algo, pero ninguno de los siguientes Q & como parecía hacer frente a esto directamente:
- 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
EDIT:
Como resultado, los ejemplos a continuación fueron de hecho funcionando como se esperaba.
Lo que no estaba claro para mí fue que cuando crear un TJSONString través de ella de constructor y agregarlo a un TJSONObject, el método ToString() devolverá un escaparon representación. Sin embargo, después de analizar un TJSONObject, el método ToString() devolverá la representación de no escapada.
La única otra advertencia era que la función EscapeString() en el código de ejemplo siguiente manejaba la comilla doble. Aunque no estaba usando la comilla doble aquí, parte de mi otro código era, y eso hizo que el análisis fallara porque TJSONString ya se escapa de ese carácter. He actualizado mi código de muestra para eliminar este manejo de la función EscapeString(), que es lo que he estado usando en mis propias clases.
Gracias de nuevo a @Linas por la respuesta, que me ayudó a "obtener".
Raw Valor de cadena:
Text := 'c:\path\name' +#13 + #10 + 'Next Line';
Text: c:\path\name
Next Line
Lo que produce DBXJSON (no se escape):
JsonString: "c:\path\name
Next Line"
JsonPair: "MyString":"c:\path\name
Next Line"
JsonObject: {"MyString":"c:\path\name
Next Line"}
análisis de texto escapado por la ONU FALLA:
Text to parse: {"MyString":"c:\path\name
Next Line"}
Parsed JsonObject = *NIL*
Lo que ESPERO DBXJSON para producir:
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"}
de análisis ESCAPED Texto (VÁLIDA) (Texto para analizar validado con JSONLint):
Text to parse: {"MyString":"c:\\path\\name\r\nNext Line"}
Parsed JsonObject.ToString(): {"MyString":"c:\path\name
Next Line"}
Me di cuenta de que el único carácter especial que TJSONString parece procesar correctamente es la comilla doble (").
Aquí está el código que estoy usando:
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.
Gracias @Linas, pero soy capaz de hacer lo mismo escapando según mi código de muestra. El otro problema es que TJsonObject no parece poder analizar la cadena JSON correctamente cuando contiene cadenas escapadas. Espero que sigo siendo yo el que está haciendo algo mal. :) – Doug
@Doug Acabo de probar con Delphi XE y todo funciona como se esperaba. Probablemente esté analizando cadena json de una manera incorrecta. Vea mi respuesta editar cómo se debe hacer. – Linas
Gracias @Linas. Después de examinar mi código con más detalle, encontré que mi rutina de escape manejaba la comilla doble (\ "). El problema es que TJSONString ya maneja este caso, y terminó agregando un escape adicional (\\"), que causó el análisis para fallar Después de eliminar este caso, todo funcionó bien. He actualizado mi ejemplo para arreglar esto. – Doug