2012-07-16 3 views
8

안녕하세요!JSON을 TListBox로 파싱

저는 현재 데스크톱 용 CloudFlare 클라이언트를 구성하려고합니다. API에 연결하여 POST 요청 (결과는 TMemo에 출력 됨)을 사용하여 JSON 결과를 성공적으로 검색했습니다. 이제이 결과를 TListBox으로 구문 분석하려고합니다 (예 : 굵게 표시된 부분 참조). 프로젝트는 Firemonkey으로 설계되었습니다.

다음은 몇 가지 예시 콘텐츠가 포함 된 형식화 된 응답 레이아웃입니다.

{ 
- response: { 
    |- ips: [ 
     |- { 
     ip: "xxx.xxx.xxx.xxx", 
     classification: "threat", 
     hits: xx, 
     latitude: null, 
     longitude: null, 
     zone_name: "domain-example1" 
     }, 
     - { 
     ip: "yyy.yyy.yyy.yyy", 
     classification: "robot", 
     hits: yy, 
     latitude: null, 
     longitude: null, 
     zone_name: "domain-example2" 
     } 
     ] 
    } 
    result : "success", 
    msg: null 
} 

내가 해봤 여러 가지 구성 요소 - SuperObject, Paweł Głowacki's JSON Designtime Parser, Tiny-JSON, LKJSON과는 DBXJSON 내장되어 있습니다. 그러나 JSON에 대한 경험이 전혀 없기 때문에 내가 시작할 수있는 가장 기본적인 예제를 찾을 수없는 것 같습니다. 많은 사람들이 샘플 데이터를 보여 주지만, 내가 시도한 모든 것들은 예상대로 작동하지 않는 것 같습니다. 왜냐하면 내가 오해하고 있기 때문입니다. 구성 요소가 작동한다고 가정하므로 시작할 때 지침이 필요합니다.

ips "배열"에는 수백 개, 종종 수천 개의 결과가 있습니다 (올바른 것이 아니라면 사과합니다. 배열로 알려져 있지만 다시 JSON을 처음 사용하는 경우).

내가 정말로 찾고있는 것은 내가 (구문 분석을 위해 사용하는 구성 요소와 함께) 빌드 할 수있는 매우 기본적인 샘플 코드 다. 내가 JSON 결과에서 모든 ip을 잡아, 그리고 TListBox (사용 TListBox.add 방법)에 별도의 항목으로 각 1 점을 추가하는 듯 싶었다 예를 들어

은, 내가 어떻게 이것을 달성 가겠어요? 난 ip 말할 때

, 난 값 (상기 레이아웃 포맷이이 xxx.xxx.xxx.xxx 또는 yyy.yyy.yyy.yyy 것)을 의미한다.

또한, 나는 "레코드"는 델파이 배열에 JSON 결과와 출력 데이터에서 IP있어 직접 확인하기를 원한다면 (?) - 예컨대을;

Result : Array of String = ['"xxx.xxx.xxx.xxx"','"threat"','xx','null','null','"domain-example1"']; 

은 JSON에서 가능합니까? (이 질문이 별도의 질문으로 보이거나 너무 관련이없는 경우 질문 전체를 닫지 말고 편집하십시오.)

내가이에 도착 가장 가까운뿐만 아니라 IP의,하지만 별도의 TListItem (즉 response, ips, ip, classification, xxx.xxx.xxx.xxx 데이터의 다른 모든 부분이 있고 다른 모든는 여러 빈 항목과 함께 자신의 항목입니다했다 비어 있지 않은 각 항목 사이에 있음).

나는 그것을 할 매우 간단 확신하지만 형식에 새로운 사람들을 위해 조금 압도 것을 JSON에 너무 많은 정보가있다.

최고 감사합니다, 스콧 프 리처드.

답변

8

JSON은 기본 개념을 이해하고 나면, 파악하는 매우 간단하고 쉽습니다. 물건을 설명하는 http://json.org을보십시오.4 개 기본 개념 JSON 거기

있다 : 기본 문자열이나 숫자 배열 또는 개체 :

어떤 JSON 요소이다. 값들의 정렬 된 목록 (. 아무것도하지만)

배열 친숙한 개념이 될 것이다. 델파이 배열과의 가장 큰 차이점은 JSON 배열에는 요소에 대해 정의 된 유형이 없다는 것입니다. 그것들은 단순히 "JSON 값의 배열"입니다.

은 키 - 값 쌍입니다. 키는 문자열 또는 숫자가 될 수 있으며 값은 JSON 값이 될 수 있습니다.

개체은 JSON 쌍의 연관지도입니다. 개념적으로는 TDictionary<string, JSON value>이라고 생각할 수 있습니다. 나는 그런 데이터의 JSON 배열을하고, TListBox에 넣어 원하는 경우

그래서, 이런 식으로 뭔가 할 것 (DBXJSON 예를 경고 : 테스트하지) : 다음

procedure TMyForm.LoadListBox(response: TJSONObject); 
var 
    i: integer; 
    ips: TJSONArray; 
    ip: TJSONObject; 
    pair: TJSONPair; 
begin 
    ListBox.Clear; 
    pair := response.Get('ips'); 
    if pair = nil then 
    Exit; 
    ips := pair.value as TJSONArray; 
    for i := 0 to ips.size - 1 do 
    begin 
    ip := ips.Get(i) as TJSONObject; 
    pair := ip.Get('ip'); 
    if pair = nil then 
     ListBox.AddItem('???', ip.Clone) 
    else ListBox.AddItem(pair.JsonString, ip.Clone); 
    end; 
end; 

IP 주소 목록과 사용자가 하나를 선택할 때 얻을 수있는 전체 레코드가 포함 된 관련 개체가 있습니다. (각 레코드의 전체 내용을 목록 컨트롤에 넣으려면 TListView을보십시오. TListBox보다 좋습니다.)

그리고 모든 값을 포함하는 문자열 배열을 만들려는 경우

function JsonObjToStringArray(obj: TJsonObject): TArray<string>; 
var 
    i: integer; 
begin 
    SetLength(result, obj.Size); 
    for i := 0 to obj.Size - 1 do 
    result[i] := obj.Get(i).JsonValue.ToString; 
end; 

이것은 모두 예제 코드입니다.

+0

많은 감사 메이슨! 대답은 훌륭하고 개념을 이해합니다. 나는 약간 혼란 스럽다. 원래 질문에 대해 충분히 설명하지 않았지만 (나는 오프너에서 그렇게 말했지만 질문이 끝나면 잊어 버리기 쉽다). 나는 TMemo에서 평문 JSON (즉, API를 통해 검색된 파싱되지 않은 문자열)을 가져 왔으며이를 'lines.text'를 프로 시저가 요구하는'JSONObject' 응답. 또한,'ips : = pair.value as TJSONArray'는'E2015 - Operator not applicable'을 반환합니다. –

+1

@scott :'TJSONObject.Parse'를보세요. 그리고 그 라인은'pair.JsonValue'를 대신 사용해야합니다. 내 잘못이야. –

+0

미래의 참고 자료 (그리고 그것을 찾고있는 다른 누구나)를 위해 예제가 작동하기 위해서는 uses 절에'System.JSON' 유닛을 포함시켜야합니다 –

1

EDIT2 : AV 매우 쉽게 수정되었습니다.

편집 : 내 자신의 코드를 자세히 검토 한 결과 엄청난 양의 메모리 누수가 발생한다는 것을 깨달았습니다. 그러나 이후로 나는 SuperObject으로 전환했으며 동일한 결과가 2 개의 변수와 메모리 누수가없는 2 줄의 코드에서 얻을 수 있음을 알았습니다.

Procedure ParseIPs; 
    ISO : ISuperObject; 
    MyItem : ISuperObject; 
begin 
    ISO := SO(RetrievedJSON); 
    for MyItem in ISO['response.ips'] do Memo2.Lines.Add(MyItem.S['ip']); 
end; 

RetrievedJSON 간단히 파싱되지 않은 평문 JSON 함유 string (즉 아닌 JSONString하지만 실제 문자열).

연속성을 위해 원본 코드를 그대로 두었습니다.

이전 대답 메이슨 휠러의 지원뿐만 아니라 question 9608794에 "테란"에서 제공하는 답변으로

, 내가 성공적으로 실제 수준까지 분석 할 다음과 같은 기본 (즉,데이터를 포함하는 "배열")에 액세스해야하고 특정 JSONString.Value이있는 모든 항목을 목록 상자 (아래 샘플에서는 LB1)에 출력해야합니다.

Procedure ParseIP; 
var 
    o, Jso, OriginalObject : TJSONObject; 
    ThePair, JsPair : TJSONPair; 
    TheVal, jsv : TJSONValue; 
    jsArr : TJsonArray; 
    StrL1 : String; 
    i, num : Integer; 
begin 
    num := 0; 
    o := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(Memo1.Text), 0) as TJSONObject; 
    ThePair := o.Get('response'); 
    TheVal := ThePair.JsonValue; 
    STRL1 := TheVal.ToString; 
    JSV := TJSONObject.ParseJSONValue(STRL1); 
    OriginalObject := JSV as TJSONObject; 
    JSPair := OriginalObject.Get('ips'); 
    JSARR := JSPair.JsonValue as TJSONArray; 
    for i := 0 to JsArr.Size-1 do 
    begin 
     JSO := JSArr.Get(i) as TJSONObject; 
     for JSPAIR in JSO do 
     begin 
     num := num+1; 
      if JSPAIR.JsonString.Value = 'ip' then 
      begin 
      LB1.Items.Add(JSPair.JsonValue.Value); 
      end 
      else null; 
     end; 
    end; 
    ShowMessage('Items in listbox: ' + IntToStr(LB1.Items.Count)); 
    ShowMessage('Items in JSON: ' + IntToStr(num div JSO.Size)); 
    Jsv.Free; 
end; 

이 그 일의 매우 라운드에 대한 방법이지만, 그것은 나에게 각 단계에서보고, 그것은 JSON을 통해 극단적 쉽게 아래로 반복 어디를 참조하고,로를 변경할 수 있습니다 함수를 어디에 여러 기준 중 하나를 기반으로 모든 조각 또는 데이터 범위를 결과로 출력 할 수 있습니다. 나는 정확한 수의 항목을 가지고 있는지 확인하기 위해 끝에 ShowMessage 루틴을 추가했습니다. 하나는 목록 상자의 항목이고 하나는 구문 분석 한 "ip"데이터의 인스턴스 수입니다.

이 코드

는 특히 그들이 검색된 정확히 같은 TMemo로 출력했다 CloudFlare API JSON 결과와 Firemonkey에서 테스트되었습니다 (함께 물론, &calls_left&a=zone_ips&class=t&geo=1 API 호출에 zone, token 및 이외에 추가 email). 다른 많은 API 호출의 다른 결과와도 작동하도록 수정하는 것이 상대적으로 쉽습니다.

명확히하기 위해, 나는 Mason의 코드를 시도했지만, 불행히도 나는 그것을 작동시킬 수 없었다. 그러나 나는 기초에 대한 설명이 그 가치가 있다는 기초 위에서 당분간 그의 대답을 받아 들였고, 최종 해결책을 얻고 내가 스스로를 만들고 가르 칠 수있는 것을 생각해 내는데 도움이되었다.