JSON 함수 작업하기

FileMaker Pro는 사용자의 맞춤형 App이 다른 FileMaker 함수 또는 다른 소스(예: REST API를 통해 JSON 포맷 데이터를 전송하는 웹 서비스)의 JSON 데이터를 분석하고 수정할 수 있게 하는 몇 가지 텍스트 함수를 제공합니다.

JSON 데이터 포맷에 대한 자세한 정보는 json.org를 참조하십시오.

이 주제에서 제공하는 예제는 REST API를 통해 클라이언트가 JSON 형식으로 제품 목록을 사용할 수 있도록 하는 베이커리의 JSON 데이터를 사용합니다. 다음은 $$JSON 변수의 JSON 데이터로 오늘의 특별 메뉴 목록을 반환합니다.

복사
변수 설정 [ $url ; "https://bakery.example.com/rest/api/products" ]
복사
URL에서 삽입 [ 대화상자 사용: 끔; 대상: $$JSON ; $url ; SSL 인증서 확인 ; cURL 옵션: "--data 목록=특별 메뉴" ]

$$JSON에서 반환되고 해당 예제에서 사용되는 데이터는 JSON 데이터 예제를 참조하십시오.

JSON 데이터 포맷 설정하기

JSON 데이터는 요소 사이에 공백이나 라인 엔딩이 필요하지 않습니다. 하지만 문제를 디버그하는 동안 데이터를 읽기 쉽게 하려면 JSONFormatElements 함수를 사용합니다. 이는 JSON 데이터 예제에 있는 것처럼 탭과 라인 엔딩 문자를 추가해 줍니다.

JSON 데이터 분석하기

다음 JSON 함수를 사용하여 JSON 데이터(더 작업할 수 있는 키, 값 또는 전체 JSON 대상체 또는 배열)를 분석합니다.

  • JSONGetElement – 요소의 JSON 데이터에 쿼리 수행(대상체, 배열 또는 값)

  • JSONListKeys – 대상체 이름(키) 나열 또는 JSON 데이터의 인덱스 배열

  • JSONListValues – JSON 데이터의 값 나열

이 함수의 첫 번째 매개 변수 json은 유효한 JSON 데이터를 포함하는 텍스트 필드, 변수 또는 텍스트 표현식을 지정하여 수행합니다.

두 번째 매개 변수, 키 또는 인덱스 또는 경로는 JSON 데이터의 부분이 다음을 수행하도록 지정합니다.

  • 키 – JSON 대상체의 키 이름

  • 인덱스 - JSON 배열에 있는 요소의 인덱스(첫 번째 요소의 인덱스는 0임)

  • 경로 - 키 이름, 배열 인덱스 또는 둘 모두의 계층형 문자열

키 또는 인덱스 또는 경로 매개 변수에 대해 다음 2개의 구문 유형(점 표기법괄호 표기법)이 지원됩니다.

키 또는 인덱스 또는 경로 매개 변수에 대한 구문

의미

점 표기법 괄호 표기법

"."

""

첫 번째 문자인 경우 루트 레벨(점 표기법 선택 사항)

".[n]"

"[n]"

루트 레벨에 있는 배열의 인덱스 n에 있는 요소

".name"

"['name']"

루트 레벨에 있는 name이라는 이름의 대상체의 키

".nameA.nameB.nameC"

"['nameA']['nameB']['nameC']"

nameBnameA의 하위 항목인 nameC이라는 이름의 대상체

".[3][2][1]nameA[0]"

"[3][2][1]['nameA'][0]"

nameA 대상체(중첩된 배열 세트의 레벨 3에 있음)에 있는 배열의 첫 번째 요소

"[:]"

"[:]"

배열의 마지막 요소

"[+]"

"[+]"

배열의 마지막 요소 이후의 위치입니다. JSONSetElement 함수에서 배열 끝에 요소를 추가합니다.

점 표기법과 괄호 표기법의 차이점은 괄호 표기법이 마침표(.)를 사용하여 키 이름을 구분하는 대신 작은 따옴표(')와 괄호([])로 키 이름을 둘러싼다는 것입니다. 키 또는 인덱스 또는 경로에서 두 표기법 중 하나를 사용할 수 있습니다. 하지만 키 이름에 마침표가 포함되어 있는 경우 JSON 파서가 전체 키 이름을 올바르게 식별할 수 있도록 괄호 표기법을 사용해야 합니다. 예를 들어 JSON 대상체의 루트에 있는 키가 "layout.response"인 경우, 키 또는 인덱스 또는 경로"['layout.response']"입니다.

다음의 예제 스크립트는 JSON 배열의 각 제품에 대해 하나의 레코드를 생성합니다. JSON 데이터 예제가 $$JSON 변수에 저장되어 있다고 가정하면, 스크립트는 JSONListValues를 사용하여 값 목록으로 제품 배열의 콘텐츠를 가져오며 ValueCount를 사용하여 목록에 있는 제품의 수를 판단합니다. 매번 루프를 통해 제품 레코드를 생성하면서 스크립트는 GetValue를 사용하여 목록의 제품에 대한 JSON 대상체를 가져오며 JSONGetElement를 사용하여 얻은 값을 매기는 필드를 설정합니다. JSON 함수는 전달된 JSON 대상체 전체를 분석하므로 여러 번 반복되는 루프 내의 작은 JSON 대상체에 대해 JSON 함수를 사용하는 것이 더욱 효율적일 수 있습니다.

복사
변수 설정 [ $ProductList ; 값: JSONListValues ( $$JSON ; "제과.제품" ) ]
변수 설정 [ $ProductCount ; 값: ValueCount ( $ProductList ) ]
변수 설정 [ $i; 값: 1 ]
If [ $ProductCount > 0 ]
   Loop [ 지우기: 항상 ]
      새로운 레코드/요청
      변수 설정 [ $Product ; 값: GetValue ( $ProductList ; $i ) ]
      필드 설정 [ 제품::ID ; JSONGetElement ( $Product ; "id" ) ]
      필드 설정 [ 제품::가격 ; JSONGetElement ( $Product ; "가격" ) ]
      필드 설정 [ 제품::재고 ; JSONGetElement ( $Product ; "재고" ) ]
      레코드/요청 커밋 [ 대화상자 사용: 끔 ]
      변수 설정 [ $i ; 값: $i + 1 ] 
      Exit Loop If [ $i > $ProductCount ]
   End Loop
End If

JSON 데이터 요소 변경 및 추가하기

JSON 데이터에 요소를 추가하고 값을 변경하려면 JSONSetElement 함수를 사용합니다. json키 또는 인덱스 또는 경로 매개 변수는 이 함수에서 JSON 데이터 분석하기에 설명된 것처럼 동작합니다. 키 또는 인덱스 또는 경로가 존재하는 요소를 지정하는 경우, 해당 요소의 값이 변경됩니다. 존재하지 않는 요소를 지정하는 경우 값이 추가됩니다.

JSONSetElement는 매개 변수에 지정된 요소를 설정합니다. 간단한 문자열이나 숫자부터 복잡한 대상체나 배열까지 유효한 모든 JSON 값을 지정할 수 있습니다.

유형 매개 변수는 의 데이터 유형을 지정하여 각 데이터 유형을 처리할 때 JSON 파서가 엄격한 규칙을 따르도록 합니다. 지원되는 데이터 유형은 JSONSetElement 함수를 참조하십시오. 데이터를 유효한 JSON 요소로 포맷된 json에 삽입하려면, 유형JSONRaw로 설정합니다.

다음 예제는 비어있는 JSON 대상체에 새로운 제품에 대한 키 값의 쌍을 추가합니다. 그런 다음, 새로운 대상체는 $$JSON 변수에 있는 제품 배열의 맨 끝에 추가됩니다(JSON 데이터 예제 참조).

복사
변수 설정 [ $NewProduct ; 값: 
   JSONSetElement ( "{}" ;
      [ "id" ; "FB4" ; JSONString ] ; 
      [ "이름" ; "바닐라 케이크" ; JSONString ] ; 
      [ "가격" ; 17.5 ; JSONNumber ] ; 
      [ "재고" ; 12 ; JSONNumber ] ; 
      [ "범주" ; "케이크" ; JSONString ] ; 
      [ "특별 메뉴" ; true ; JSONBoolean ] 
   ) ]
변수 설정 [ $NextIndex ; 값: 
   ValueCount ( 
      JSONListKeys ( $$JSON ; "제과.제품" ) 
   ) ] 
변수 설정 [ $$JSON ; 값: 
   JSONSetElement ( 
      $$JSON ; "제과.제품[" & $NextIndex & "]" ; $NewProduct ; 
      JSONObject 
   ) ]

JSON 요소를 생성하는 또 다른 JSON 함수는 JSONMakeArray 함수입니다. 이 함수는 값 목록을 JSON 배열로 변환합니다. 다양한 방식으로 포맷된 데이터를 수락하기 위해 이 함수를 사용하면 각 값을 구분하는 문자와 사용할 JSON 데이터 유형을 지정할 수 있습니다.

JSON 데이터 요소 삭제하기

요소를 삭제하려면 JSONDeleteElement 함수를 사용합니다. json키 또는 인덱스 또는 경로 매개 변수는 이 함수에서 JSON 데이터 분석하기에 설명된 것처럼 동작합니다. 키 또는 인덱스 또는 경로 매개 변수는 반드시 json에 있는 요소를 지정해야 합니다.

다음 예제는 $$JSON 변수의 "id" 키에 "FB3" 값이 있는 제품 배열의 요소를 삭제합니다(JSON 데이터 예제 참조).

복사
변수 설정 [ $ProductCount ; 값: 
   ValueCount ( 
      JSONListKeys ( $$JSON ; "제과.제품" ) 
   ) ] 
변수 설정 [ $i ; 값: 0 ]
If [ $ProductCount > 0 ]
   Loop [ 지우기: 항상 ]
      변수 설정 [ $ID ; 값: 
         JSONGetElement ( $$JSON ; "제과.제품[" & $i & "]id" ) ]
      If [ $ID = "FB3" ]
         변수 설정 [ $$JSON ; 값: 
            JSONDeleteElement ( $$JSON ; "제과.제품[" & $i & "]" ) ]
         스크립트 종료 [ 텍스트 결과 0 ]
      End If
      변수 설정 [ $i ; 값: $i + 1 ]
      Exit Loop If [ $i ≥ $ProductCount ]
   End Loop
End If

JSON 성능 최적화

JSON 함수가 텍스트 입력을 구문 분석할 때마다, JSON 파서는 나중에 JSON을 더 빠르게 처리하기 위해 텍스트가 아닌 이진 표현을 생성합니다. JSON을 구문 분석하고 캐시하는 자동 메커니즘과 명시적 메커니즘으로 JSONParse 함수가 있습니다.

자동 JSON 캐싱 활용

구문 분석은 시간이 걸리므로 JSON 함수는 마지막으로 구문 분석된 JSON의 이진 표현을 메모리에 캐시합니다. 이렇게 하면 나중에 동일한 JSON을 다시 구문 분석해야 할 경우가 줄어듭니다. 하나의 자동 캐시만 유지됩니다. 다른 JSON 값이 구문 분석되면 이전에 캐시된 JSON 값은 버려집니다. 구문 분석된 JSON은 변수, 스크립트 매개 변수 및 계산과 같은 메모리에만 존재합니다. 필드 값을 설정하는 데 사용되는 경우, 값이 필드에 텍스트로 저장됩니다.

이 예제는 줄 번호를 기준으로 처음에 $JSON1과 $JSON2에 저장된 JSON 텍스트가 구문 분석되는 경우와 구문 분석되지 않는 경우를 보여줍니다.

복사
변수 설정 [ $id ; JSONGetElement ( $JSON1 ; "id" ) ]
변수 설정 [ $name ; JSONGetElement ( $JSON1 ; "name" ) ]
변수 설정 [ $price ; JSONGetElement ( $JSON2 ; "price" ) ]
변수 설정 [ $category ; JSONGetElement ( $JSON1 ; "category" ) ]
  1. $JSON1이 구문 분석되고 이진 표현이 캐시에 저장됩니다.

  2. $JSON1은 다시 구문 분석할 필요가 없습니다.

  3. $JSON2는 이전에 캐시된 값을 대체하여 구문 분석되고 캐시됩니다.

  4. $JSON1은 더 이상 캐시되지 않았으므로 다시 구문 분석됩니다.

따라서 자동 캐싱을 활용하려면 한 번에 하나의 JSON 값을 처리하는 것이 가장 좋습니다. (위의 예제에서는 $JSON1을 다시 구문 분석하지 않도록 줄 3과 줄 4를 교환합니다.)

JSONParse 사용

JSON 값의 이진 표현을 변수와 자동 캐시에 구문 분석하고 명시적으로 저장하려면 JSONParse 함수를 사용하십시오. 함수의 json 매개 변수는 필드나 문자열에서 JSON으로 포맷된 텍스트이든, 변수에서 이미 구문 분석된 JSON이든 상관 없이 JSON 데이터로 평가하는 모든 텍스트 표현식입니다.

다음 예제는 JSON 텍스트를 구문 분석합니다.

복사
변수 설정 [ $JSON1 ; "{ \"product\": {\"id\": \"FB1\"} }" ]
변수 설정 [ $JSON1 ; JSONParse ( $JSON1 ) ]
  1. $JSON1은 다음과 같은 텍스트 표현일 뿐입니다.

    { "product": {"id": "FB1"} }

  2. JSONParse를 사용한 후:

    • 자동 캐시에는 이진 표현이 포함됩니다.

    • $JSON1 변수는 텍스트와 이진 표현을 모두 포함합니다.

JSONParse가 사용되지 않는 경우, 이 예제에서는 다음과 같습니다.

복사
변수 설정 [ $JSON1 ; "{ \"product\": {\"id\": \"FB1\"} }" ]
변수 설정 [ $JSON2 ; JSONGetElement ( $JSON1 ; "product") ]
  1. $JSON1은 이전과 마찬가지로 텍스트 표현일 뿐입니다.

  2. JSONGetElement를 사용한 후:

    • 자동 캐시에는 이진 표현이 포함됩니다.

    • $JSON2는 {"id": "FB1"}의 이진 표현을 포함합니다.

    • $JSON1은 여전히 텍스트 표현일 뿐입니다. 텍스트는 구문 분석되었지만 이진 표현은 자동 캐시에만 있습니다.

JSONParse를 추가할 경우의 결과와 비교해 보십시오.

복사
변수 설정 [ $JSON1 ; "{ \"product\": {\"id\": \"FB1\"} }" ]
변수 설정 [ $JSON1 ; JSONParse ( $JSON1 ) ]
변수 설정 [ $JSON2 ; JSONGetElement ( $JSON1 ; "product") ]
  1. $JSON1은 이전과 마찬가지로 텍스트 표현일 뿐입니다.

  2. JSONParse를 사용한 후:

    • 자동 캐시에는 이진 표현이 포함됩니다.

    • $JSON1은 텍스트와 이진 표현을 모두 포함합니다.

  3. JSONGetElement를 사용한 후:

    • $JSON2는 {"id": "FB1"}의 이진 표현을 포함합니다.

      텍스트 표현은 현재 $JSON2에 저장되지 않으며, 나중에 필요할 때만 생성됩니다.

JSONGetElement는 줄 2에서 $JSON1로 캐시된 이진 표현을 사용할 수 있으므로 줄 3에서 $JSON1을 구문 분석할 필요가 없다는 점에 유의하십시오.

텍스트를 구문 분석하여 이진 표현을 가져오는 데 시간이 걸리는 것과 마찬가지로 이진 JSON을 텍스트로 변환하는 데도 시간이 걸립니다. 따라서 JSONGetElement 및 JSONSetElement와 같은 JSON 함수의 결과는 이진 표현일 뿐입니다. 텍스트 표현은 변수(예: $JSON2)를 필드에 저장하거나 데이터 뷰어에서 변수를 볼 때와 같이 필요할 때만 생성됩니다.

companion 함수 JSONParsedState를 사용하면 제공된 JSON 값이 함께 저장된 JSON을 구문 분석했는지 여부, JSON의 유효성 및 JSON 유형을 확인할 수 있습니다.

모범 사례

대규모 JSON 구조를 반복적으로(특히 루프에서) 처리하거나 JSON 데이터의 여러 요소로 작업할 경우, 작업 순서에 따라 성능에 상당한 차이가 생길 수 있습니다.

자동 JSON 캐싱을 활용하려면 한 필드에서 JSON 데이터를 로드하여 작업하고 다른 필드로 전환한 다음, 다시 첫 번째 필드로 돌아가 작업하지 않는 것이 가장 좋습니다. JSON 함수가 다른 JSON 텍스트를 처리할 때마다 이전에 캐시된 JSON은 버려지므로 텍스트를 다시 구문 분석해야 합니다. 예를 들어, 다음과 같이 하면 성능이 가장 느려집니다.

복사
# 예제 - 효율적이지 않음
변수 설정 [ $namel ; 값: JSONGetElement ( 테이블::JSON1 ; "name" ) ]
변수 설정 [ $name2 ; 값: JSONGetElement ( 테이블::JSON2 ; "name" ) ]
변수 설정 [ $id1 ; 값: JSONGetElement ( 테이블::JSON1 ; "id" ) ]
변수 설정 [ $id2 ; 값: JSONGetElement ( 테이블::JSON2 ; "id" ) ]

다른 JSON 데이터에서 작업하기 전에 동일한 JSON 데이터에서 모든 작업을 수행하도록 단계를 재정렬하면 자동 캐시가 유리하게 작동하여 동일한 필드에서 데이터를 두 번 구문 분석할 필요가 없습니다.

복사
# 예제 - 효율적
변수 설정 [ $namel ; 값: JSONGetElement ( 테이블::JSON1 ; "name" ) ]
변수 설정 [ $id1 ; 값: JSONGetElement ( 테이블::JSON1 ; "id" ) ]
변수 설정 [ $name2 ; 값: JSONGetElement ( 테이블::JSON2 ; "name" ) ]
변수 설정 [ $id2 ; 값: JSONGetElement ( 테이블::JSON2 ; "id" ) ]

최상의 성능을 보여주는 가장 유연한 방법은 JSONParse 함수를 사용하여 각 소스에서 JSON 텍스트를 가져와 구문 분석한 다음 변수에 저장하는 것입니다. 이렇게 하면 한 번만 구문 분석됩니다. 그러면 JSON 함수가 이미 구문 분석된 이진 표현을 포함하는 변수를 사용할 수 있으므로 추가 작업(예: 요소 가져오기 또는 설정)을 어떤 순서로 수행하더라도 성능에 영향을 주지 않습니다.

복사
# 예제 - 최상
변수 설정 [ $JSON1 ; 값: JSONParse ( 테이블::JSON1 ) ]
변수 설정 [ $JSON2 ; 값: JSONParse ( 테이블::JSON2 ) ]

변수 설정 [ $namel ; 값: JSONGetElement ( $JSON1 ; "name" ) ]
변수 설정 [ $name2 ; 값: JSONGetElement ( $JSON2 ; "name" ) ] 
변수 설정 [ $id1 ; 값: JSONGetElement ( $JSON1 ; "id" ) ]
변수 설정 [ $id2 ; 값: JSONGetElement ( $JSON2 ; "id" ) ]

JSON 데이터에 있는 오류 처리하기

json 매개 변수를 분석하는 동안 오류가 발생한 경우, JSON 함수는 "?"과 함께 JSON 파서의 오류 메시지를 반환합니다.

예를 들어 "제과" 키 다음에 ":"가 JSON 데이터 예제에서 빠진 경우 이 계산은

복사
JSONGetElement ( $$JSON ; "제과.제품[0]id" )

다음 오류 메시지를 반환합니다.

복사
? * Line 3, Column 2
  Missing ':' after object member name
* Line 13, Column 5
  Extra non-whitespace after JSON value.

JSON 데이터를 사용하기 전에 데이터가 유효한지 확인하려면 JSONFormatElements 함수를 사용하고 첫 번째 문자가 "?"인지 테스트합니다. 예를 들어 다음과 같습니다.

복사
변수 설정 [ $result ; 값: JSONFormatElements ( $$JSON ) ]
If [ Left ( $result ; 1 ) = "?" ]
   # $$JSON에 유효하지 않은 JSON 데이터가 있습니다.
End If

또는 JSONGetElementType 함수를 통해 먼저 JSON 데이터가 유효한지 여부와 특정 JSON 유형을 확인한 후에 사용할 수 있습니다. 예를 들어, $$JSON이 유효한 JSON 대상체인지 테스트하려면 다음을 수행하십시오.

복사
변수 설정 [ $result ; 값: JSONGetElementType( $$JSON, "" ) ]
If [ $result ≠ JSONObject ]
    # $$JSON에 유효하지 않은 JSON 데이터가 있습니다.
End If

오류를 감지하는 또 다른 방법은 JSONParsedState 함수를 사용하는 것입니다. 이 함수를 통해 JSON 데이터가 구문 분석되었는지와 유효한지 여부 및 해당할 경우 JSON 데이터 유형을 확인할 수 있습니다.

복사
변수 설정 [ $result ; 값: JSONParse ( $$JSON ) ]
}변수 설정 [ $ParsedState ; 값: JSONParsedState ( $result ) ]
If [ $ParsedState < 0 ]
    # $$JSON이 구문 분석되었지만 유효하지 않은 JSON 데이터가 포함되어 있습니다.
Else If [ $ParsedState = 0 ]
    # $$JSON이 구문 분석되지 않았습니다.
Else If [ $ParsedState > 0 ]
    # $$JSON이 구문 분석되었으며 유효합니다. $ParsedState는 JSON 유형을 나타냅니다.    변수 설정 [ $type ; 값: 
        Case ( 
          $ParsedState = JSONString ; "JSON 유형은 JSONString입니다" ;
          $ParsedState = JSONNumber ; "JSON 유형은 JSONNumber입니다" ;
          $ParsedState = JSONObject ; "JSON 유형은 JSONObject입니다" ;
          $ParsedState = JSONArray ; "JSON 유형은 JSONArray입니다" ;
          $ParsedState = JSONBoolean ; "JSON 유형은 JSONBoolean입니다" ;
          $ParsedState = JSONNull ; "JSON 유형은 JSONNull입니다"
        )
    ]
    사용자 설정 대화상자 보기 [ $type ]
End If

JSON 데이터 예제

다음 JSON 데이터 예제는 각 키 값의 쌍이 여러 개 있는 3개의 "제품" 대상체 배열의 "제과" 대상체를 포함합니다.

복사
{
    "제과"
    {
        "제품"
        [
            {
                "id" : "FB1",
                "이름" : "도너츠",
                "가격" : 1.99,
                "재고" : 43,
                "범주" : "빵",
                "특별 메뉴" : true
            },
            {
                "id" : "FB2",
                "가격" : 22.5,
                "이름" : "초콜릿 케이크",
                "재고" : 23,
                "범주" : "케이크"
                "특별 메뉴" : true
            },
            {
                "id" : "FB3",
                "가격" : 3.95,
                "이름" : "바게트",
                "재고" : 34,
                "범주" : "빵"
                "특별 메뉴" : true
            }
        ]
    }
}

참고 

  • JSON 파서는 배열에서 요소의 순서를 유지하지만 대상체에 있는 요소의 순서는 유지하지 않습니다. 그러므로 JSON 함수는 대상체에 있는 요소를 지정된 순서와는 다른 순서로 반환합니다.

  • JSON 데이터에서는 사용자의 컴퓨터 시스템 포맷이나 FileMaker Pro 파일이 생성되었을 때 사용된 포맷에서 지정된 구분 기호와 상관없이, 소수 값은 반드시 소수 구분 기호로 마침표(".")를 사용해야 합니다.