2012-08-02 65 views
12

我無法轉換字符串轉義字符 a TJsonString。 (我正在使用Delphi XE 2,更新4,修補程序1)。如何使用DBXJSON將字符串與帶有轉義/特殊字符的JSON轉換?

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

看起來TJSONString在通過ToString()方法返回JSON表示時沒有正確轉義。

我做錯了什麼(如果有的話),我如何正確地將字符串轉換爲正確的JSON表示?

也許我錯過了一些東西,但沒有以下是問答&作爲似乎直接解決這個問題:

編輯:

事實證明,下面的例子確如預期工作。

是什麼我也不清楚的是,當通過它的構造函數創建一個和TJSONString將其添加到TJSONObject的ToString()方法會返回一個逃脫表示。但是,在解析後得到一個TJSONObject,ToString()方法將返回未經轉義的表示。

唯一的其他警告是下面示例代碼中的EscapeString()函數處理雙引號。雖然我沒有在這裏使用雙引號,但是我的其他一些代碼是,並且導致解析失敗,因爲TJSONString已經轉義了該字符。我已經更新了我的示例代碼,以從EscapeString()函數中刪除此處理,這是我在自己的類中使用的。

再次感謝@Linas的答案,這幫助我「得到」它。

原始字符串值:

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

Text: c:\path\name 
Next Line 

什麼DBXJSON產生(NO 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* 

的處置 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. 

回答

7

你可以試着定義自己的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; 

用例:

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; 

這是解析應該怎麼做:

//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; 
+0

感謝@Linas,但我能夠做自己逃脫按我的示例代碼。另一個問題是,當TJsonObject包含轉義字符串時,似乎無法正確解析JSON字符串。我希望這仍然是我做錯了事。 :) – Doug 2012-08-02 23:13:08

+0

@Doug只用Delphi XE測試過,一切都按預期工作。您可能以錯誤的方式解析json字符串。看到我的答案編輯它應該如何完成。 – Linas 2012-08-03 06:57:32

+0

謝謝@Linas。在更詳細地檢查我的代碼後,我發現我的轉義例程是處理雙引號(\「)。問題是TJSONString已經處理了這種情況,並最終添加了一個額外的轉義符(\\」),解析失敗。刪除這種情況後,一切正常。我已更新我的示例來解決此問題。 – Doug 2012-08-06 17:02:30

相關問題