使用DBXJSON如何使用转义/特殊字符将字符串转换为JSON? [英] How do I convert a string to and from JSON with escaped/special characters using DBXJSON?

查看:664
本文介绍了使用DBXJSON如何使用转义/特殊字符将字符串转换为JSON?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将转义的字符串转换为,从转换为TJsonString时遇到问题。 (我使用的是Delphi XE 2,Update 4,Hotfix 1)。



注意:我熟悉 SuperObject ,但我的要求是使用DBXJSON单元。



它看起来像通过ToString()方法返回JSON表示时,TJSONString未正确转义。



我做错了什么(如果有的话),如何正确转换一个字符串具有/来自其正确的JSON表示形式的特殊字符



也许我错过了一些东西,但是没有一个这样直接解决这个问题:






编辑: strong>



事实证明,下面的例子确实按照预期工作。



什么不是对于我来说,当通过它的构造函数创建 TJSONString并将其添加到TJSONObject时,ToString()方法将返回转义的表示。但是,在解析 TJSONObject之后,ToString()方法将返回未转义的表示。



只有其他注意事项是下面的示例代码中的EscapeString()函数正在处理双引号。虽然我没有在这里使用双引号,但我的其他一些代码是,并且导致解析失败,因为TJSONString已经转义了该字符。我已经更新了我的示例代码,以从EscapeString()函数中删除这个处理,这是我在自己的类中使用的。



再次感谢@ Linas的答案,这有助于我得到。


原始字符串值: p>

  Text:='c:\path\\\
ame'+#13 +#10 +'Next Line'

文本:c:\path\\\
ame
下一行

什么DBXJSON生产(NO ESCAPES):

  JsonString:c:\path \\\
ame
下一行

JsonPair:MyString:c:\path\\\
ame
下一行

JsonObject: {MyString:c:\path\\\
ame
下一行}

解析UN转义文本失败

 要解析的文本: {MyString:c:\path\\\
ame
下一行}

解析的JsonObject = * NIL *

我想要的 DBXJSON生成:

  Escaped String:c:\\path\\\\
ame\r\\\
Next行

JsonString:c:\\path \\\\\\\
Next行

JsonPair:MyString:c:\\\\\\\\\\\
Next行

JsonObject:{MyString:c: \\\\\\\\\\\\\\\\\\\\\\
Next Line}
解析ESCAPED文本( INVALID )(使用 JSONLint 验证的文本解析):

 要解析的文本:{MyString:c:\\path\\\\
ame\ r\\\
Next Line}

解析的JsonObject.ToString():{MyString:c:\path\\\
ame
下一行}
<我注意到TJSONString似乎正确处理的唯一特殊字符是双引号(),code



以下是我使用的代码:

 程序JsonTest; 

{$ APPTYPE CONSOLE}

{$ R * .res}

使用
System.SysUtils,DbxJson;

函数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
结果:='';
为ACalue的AChar $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $
$ AC $ QUOTATION_MARK:结果:=结果+ ESCAPE + QUOTATION_MARK;
REVERSE_SOLIDUS:Result:= Result + ESCAPE + REVERSE_SOLIDUS;
SOLIDUS:Result:= Result + ESCAPE + SOLIDUS;
BACKSPACE:Result:= Result + ESCAPE +'b';
FORM_FEED:结果:=结果+ ESCAPE +'f';
NEW_LINE:Result:= Result + ESCAPE +'n';
CARRIAGE_RETURN:Result:= Result + ESCAPE +'r';
HORIZONTAL_TAB:结果:=结果+ ESCAPE +'t';
else
begin
if(Integer(AChar)< 32)或(Integer(AChar)> 126)then
Result:= Result + ESCAPE +'u'+ IntToHex(整数(AChar),4)
else
结果:= Result + AChar;
结束
结束
结束
结束

程序测试;
var
文本:string;
JsonString:TJsonString;
JsonPair:TJsonPair;
JsonObject:TJsonObject;
begin
try
Writeln('Raw String Value');
Writeln('-----------------');
文本:='c:\path\\\
ame'+#13 +#10 +'下一行';
Writeln('Text:',Text);
JsonString:= TJsonString.Create(Text);
JsonPair:= TJsonPair.Create('MyString',JsonString);
JsonObject:= TJsonObject.Create(JsonPair);
// DBXJSON结果
Writeln;
Writeln(什么DBXJSON生成);
Writeln('---------------------');
Writeln('JsonString:',JsonString.ToString);
Writeln;
Writeln('JsonPair:',JsonPair.ToString);
Writeln;
Writeln('JsonObject:',JsonObject.ToString);
Writeln;

//指定JSON表示
文本:= JsonObject.ToString;
// free json object
JsonObject.Free;
//解析
JsonObject:= TJsonObject.ParseJsonValue(TEncoding.ASCII.GetBytes(
Text),0)as TJsonObject;
Writeln('解析UN转义文本*失败*');
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;
//预期结果
文本:='c:\path\\\
ame'+#13 +#10 +'下一行';
文本:= EscapeString(文本);
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;
//分配JSON表示
文本:= JsonObject.ToString;
// free json object
JsonObject.Free;
//解析它
JsonObject:= TJsonObject.ParseJsonValue(TEncoding.ASCII.GetBytes(
Text),0)as TJsonObject;
Writeln('解析ESCAPED文本(* INVALID *)');
Writeln('----------------------------------');
Writeln('Text to parse:',Text);
Writeln;
Writeln('Parsed JsonObject.ToString():',JsonObject.ToString);
Writeln;
Readln;
除了
在E:Exception do
begin
Writeln(E.ClassName,':',E.Message);
Readln;
结束
结束
结束

开始
测试;
结束。


解决方案

您可以尝试定义自己的TJSONString类型并转义json字符串在那里例如:

 使用
DBXJSON;

type
TSvJsonString = class(TJSONString)
private
函数EscapeValue(const AValue:string):string;
public
构造函数Create(const AValue:string);超载;
结束

{TSvJsonString}

构造函数TSvJsonString.Create(const AValue:string);
begin
继承Create(EscapeValue(AValue));
结束

函数TSvJsonString.EscapeValue(const AValue:string):string;

程序AddChars(const AChars:string; var Dest:string; var AIndex:Integer);一致;
begin
System.Insert(AChars,Dest,AIndex);
System.Delete(Dest,AIndex + 2,1);
Inc(AIndex,2);
结束

procedure AddUnicodeChars(const AChars:string; var Dest:string; var AIndex:Integer);一致;
begin
System.Insert(AChars,Dest,AIndex);
System.Delete(Dest,AIndex + 6,1);
Inc(AIndex,6);
结束

var
i,ix:整数;
AChar:Char;
begin
结果:= AValue;
ix:= 1;
for i:= 1 to System.Length(AValue)do
begin
AChar:= AValue [i];
case AChar
'/','\',''':
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:
开始
AddChars('\\\
',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
如果Word(AChar)> 127 then
begin
AddUnicodeChars('\u'+ IntToHex(Word (AChar),4),Result,ix);
end
else
begin
Inc(ix);
结束
结束
结束
结束
结束

使用示例:

 程序测试; 
var
LText,LEscapedText:string;
LJsonString:TSvJsonString;
LJsonPair:TJsonPair;
LJsonObject:TJsonObject;
begin
LText:='c:\path\\\
ame'+#13 +#10 +'下一行';
LJsonString:= TSvJsonString.Create(LText);
LJsonPair:= TJsonPair.Create('MyString',LJsonString);
LJsonObject:= TJsonObject.Create(LJsonPair);
try
LEscapedText:= LJsonObject.ToString;
// LEscapedText是:c:\\\\\\\\\\
Next行
finally

结束
结束

这是解析应该如何完成:

  // AText:='{MyString:c:\\\\\
ame\r\\\
Next Line}';
函数解析(const AText:string):string;
var
obj:TJSONValue;
begin
obj:= TJSONObject.ParseJSONValue(AText);
try
结果:= obj.ToString;
//结果:= {MyString:c:\path\\\
ame
//下一行}
finally
obj.Free;
结束
结束


I'm having trouble converting a string with escaped characters to and from a TJsonString. (I'm using Delphi XE 2, Update 4, Hotfix 1).

NOTE: I am familiar with the SuperObject, but my requirements are to use the DBXJSON unit.

It looks like the TJSONString is not correctly escaped when returning the JSON representation via the ToString() method.

What (if anything) am I doing wrong and how do I correctly convert a string with special characters to/from its correct JSON representation?

Perhaps I missed something, but none of the following Q&As seemed to address this directly:

EDIT:

As it turns out, the examples below were indeed working as expected.

What wasn't clear to me was that when creating a TJSONString via it's constructor and adding it to a TJSONObject, the ToString() method will return an escaped representation. However, after parsing a TJSONObject, the ToString() method will returned the un-escaped representation.

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.

Raw String Value:

Text := 'c:\path\name' +#13 + #10 + 'Next Line';

Text: c:\path\name
Next Line

What DBXJSON produces (NO ESCAPES):

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 EXPECT DBXJSON to produce:

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):

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 (").

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.

解决方案

You can try to define your own TJSONString type and escape json strings there. E.g.:

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;

这篇关于使用DBXJSON如何使用转义/特殊字符将字符串转换为JSON?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆