How do I convert a string to and from JSON with escaped/special characters using DBXJSON?

前端 未结 3 1958
长发绾君心
长发绾君心 2020-12-28 08:54

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

相关标签:
3条回答
  • 2020-12-28 08:58

    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.

    Hope this helps someone :)

    0 讨论(0)
  • 2020-12-28 08:59

    I ran into the same problem with Delphi XE2. My solution was to alter the library file Data.DBXJSON.pas. I copied the original file to my PatchedLibraryXE2 directory (who's first in my library path). Here I changed the method

    function TJSONString.ToString: UnicodeString;
    begin
      if FStrBuffer <> nil then
    //    Exit('"' + AnsiReplaceStr(FStrBuffer.ToString, '"', '\"') + '"');
        Exit('"' + EscapeValue(FStrBuffer.ToString) + '"');
      Result := NullString;
    end;
    

    I used the escape method of Linas in his answer above. I left out the escape of characters bigger than 127. To compile I also needed to copy the file Data.DBXCommon.pas to my PatchedLibraryXE2 directory. Now my TJSONObject.ToString() works as expected.

    0 讨论(0)
  • 2020-12-28 09:13

    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;
    
    0 讨论(0)
提交回复
热议问题