4

最近、JSONを解析するときに壁にぶつかりました。ご覧のとおり、CloudFlareクライアントインターフェイスAPIを使用しているときに、特定のIPの「脅威の評価」を検索したかったのです。問題は、APIの設計により、形式が次のようになることです。

{
 response: {
            xxx.xxx.xxx.xxx: <value>,
            calls_left: 299
            },
 result: "success",
 msg: null
}

xxx.xxx.xxx.xxxデータを取得するために必要なフィールド名を表します。すぐに、私が直面していた問題をおそらく見ることができます。解析文字列のドット文字は、現在のパスのサブレベルであると見なされます。

<value>IPの実際の評価を表します。ただし、形式とそこから返されるデータ型は異なります。脅威ではない、または脅威の評価がないIPではfalse、ブール値として返されます。検索エンジンのクローラーでは、文字列として"SE:<var>"<var>は数値)を返します。既知の脅威については、戻ります"BAD:<var>"(ここ<var>で、は数値です)。そのため、返される既知のデータ型に依存することはできませんでした。

ただし、主な問題は、このフィールドから値を読み取ろうとすると、フィールド名内のドットが原因で明らかに失敗することです。

4

2 に答える 2

7

ハックの必要はありません。必要なのは、AsObjectを通過することだけです。埋め込まれたドットを含む名前は、パス指定子として扱わずに使用されます。

const Line1 = '{'
      + #13#10' response: {'
      + #13#10'            xxx.xxx.xxx.xxx: "somestring",'
      + #13#10'            calls_left: "299"'
      + #13#10'            },'
      + #13#10' result: "success",'
      + #13#10' msg: null'
      + #13#10'}';

var
  super: ISuperObject;
  res: ISuperObject;
begin
  super := SO(Line1);
  res := super.O['response'];

  writeln('S[calls_left''] on res: ', res.S['calls_left']);
  writeln('S[''xxx.xxx.xxx.xxx''] on res: ', res.S['xxx.xxx.xxx.xxx']);

  writeln('Names: ', res.AsObject.GetNames.AsString);
  writeln('Values: ', res.AsObject.GetValues.AsString);

  writeln('S[''xxx.xxx.xxx.xxx''] on res: through AsObject: ',
    res.AsObject.S['xxx.xxx.xxx.xxx']);

次の結果が得られます。

S[calls_left'] on res: 299
S['xxx.xxx.xxx.xxx'] on res:
Names: ["calls_left","xxx.xxx.xxx.xxx"]
Values: ["299","somestring"]
S['xxx.xxx.xxx.xxx'] on res: through AsObject: somestring
于 2012-07-22T09:29:54.133 に答える
1

これに対する秘訣は、この「制限」の大雑把な回避策です。他の方法もあるかもしれません-これを達成するための関数がSuperObject内にあるかもしれません-しかし、これはほとんどの新しいコーダーがおそらく快適な方法でした(Delphiの新機能、コーディングの新機能、またはSuperObjectの新機能のいずれか)。StringReplace「。」を置き換える機能を利用しています。よりフィールド名に適した文字を持つインスタンス(この場合、私はを使用します*)。私が言ったように、それは大雑把な方法であり、より簡単な方法があるかもしれませんが、新しいコーダーが学ぶことができる簡単な解決策がその場所にあります。

詳細

この特定の例は現在のCloudFlareAPIのものであるため、から拡張することをお勧めします。SuperObjectが機能する必要があります。

MyJSONすでに取得されているJSONを。として表しますstring。これは、、、TMemo.textまたはTEdit.text単なる標準文字列にすることができます。

MyIP探したいIPを表します。

Function GetValue(MyJson, MyIP : String) : String;
var
  ISO : ISuperObject;
  FmIP, FmJSON : String;
begin  
  FmJSON := StringReplace(MyJSON,'.','*',[rfReplaceAll]);
  FmIP := StringReplace(MyIP,'.','*',[rfReplaceAll]);
  ISO := SO(FmJSON);
  Result := iso.s['response'+'.'+FmIP];
end;

これにより、JSONのブール値、整数、文字列のいずれであるかに関係なく、結果が文字列として返されます。ご覧のとおり、目標を完全に達成しながら理解するのは非常に簡単です。潜在的な問題は、結果にが含ま.れている場合、出力値に*その場所が含まれることです。StringReplace結果を次のように簡単にラップできます。

StringReplace(iso.s['response'+'.'+FmIP],'*','.',[rfReplaceAll]);

これから拡大

PosまたはAnsiPosを使用してIP自体の位置を見つけることにより、これから拡張できる可能性があります。それを拡張すると、最終的なキャラクターの位置を取得するのは比較的簡単であり、そのため、この特定の状況の外で使用できる関数を見つけることができます。ただし、それについて議論することは、この特定の議論ではなく、一般的な「便利な文字列関数」の答えとして役立つでしょう。

もちろん、他の答えも大歓迎です!

于 2012-07-21T23:03:27.653 に答える