Arbeta med JSON-funktionerna

FileMaker Pro erbjuder flera textfunktioner som gör att anpassade appar kan tolka och ändra JSON-data från andra från andra FileMaker-funktioner eller från andra källor, till exempel webbtjänster som överför data i JSON-format via en REST API.

Mer information om JSON-dataformatet finns i json.org.

De exempel som visas i detta ämne använder JSON-data från ett bageri som gör sin produktlista tillgänglig för kunder i JSON-format via ett REST API. Följande returnerar listan över dagens specialerbjudanden som JSON-data i $$JSON-variabeln:

Kopiera
Ange variabel [ $url ; "https://bageri.exempel.com/rest/api/produkter" ]
Kopiera
Infoga från URL [ Med dialogruta: Av; Mål: $$JSON ; $url ; Verifiera SSL-certifikat ; cURL-tillval: "--data list=specials" ]

Mer information om data som returneras i $$JSON och används i de här exemplen finns i Exempel på JSON-data.

Formatera JSON-data

JSON-data kräver inte mellanslag eller radbrytningar mellan element. Du kan däremot göra det lättare att läsa data när du debuggar problem genom att använda Funktionen JSONFormatElements, vilket lägger till tabbar och radslutstecken, som vi visar i Exempel på JSON-data.

Tolka JSON-data

Använd följande JSON-funktioner för att tolka JSON-data, dvs. för att hämta nycklar, värden eller hela JSON-objekt eller -matriser som du kan behandla vidare:

  • JSONGetElement – Frågar JSON-data om ett element (ett objekt, en matris eller ett värde.

  • JSONListKeys – Listar objektnamnen (nycklar) eller matrisindex i JSON-data

  • JSONListValues – Listar värden i JSON-data

Den första parametern för dessa funktioner, json, anger textfältet, variabeln eller textuttrycket som innehåller giltiga JSON-data att använda.

Den andra parametern, nyckelEllerIndexEllerSökväg, anger vilken del av JSON-data som ska användas:

  • nyckel – namnet på en nyckel i ett JSON-objekt

  • index – index för ett element i en JSON-matris (det första elementet har ett index på 0)

  • sökväg – en hierarkisk sträng av nyckelnamn, matrisindex eller både och

Följande två syntaxtyper för parametern nyckelEllerIndexEllerSökväg stöds: punktnotation och parentesnotation.

Syntax för parametern nyckelEllerIndexEllerSökväg

Betydelse

Punktnotation Parentesnotation

"."

""

Roten, om det är det första tecknet (valfritt i punktnotation)

".[n]"

"[n]"

Element vid index n av en matris i roten

".namn"

"['namn']"

Nyckeln till ett objekt med namnet namn i roten

".namnA.namnB.namnC"

"['namnA']['namnB']['namnC']"

Ett objekt med namnet namnC, som är underordnad namnB och namnA

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

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

Det första elementet för matrisen i objektet namnA, vilket är på den tredje nivån i en uppsättning av kapslade matriser

"[:]"

"[:]"

Det sista elementet i en matris

"[+]"

"[+]"

Positionen efter det sista elementet i en matris. Använd i Funktionen JSONSetElement för att lägga till ett element i slutet av en matris.

Skillnaden mellan punkt- och parentesnotation är att i stället för att använda punkter (.) för att separera nyckelnamn så innebär parentesnotation att nyckelnamnen omges med enkla citattecken (') och klammerparenteser ([]). Du kan använda vilken notation du vill i nyckelEllerIndexEllerSökväg. Dock måste du använda parentesnotation om nyckelnamnen innehåller punkter, så att JSON-tolken korrekt kan identifiera hela nyckelnamnet. Om till exempel en nyckel i roten till ett JSON-objekt är "layout.svar", skulle nyckelEllerIndexEllerSökväg vara "['layout.svar']".

Följande exempelscript skapar en post för varje produkt i en JSON-matris. Om vi antar att Exempel på JSON-data är lagrat i variabeln $$JSON, så använder scriptet JSONListValues för att hämta innehållet i produktmatrisen som en lista med värden och använder ValueCount för att avgöra antalet produkter i listan. Scriptet skapar en post för en produkt varje gång per loop och använder GetValue för att hämta JSON-objektet för en produkt från listan och anger fälten till de värden som hämtats med hjälp av JSONGetElement. Eftersom JSON-funktionerna tolkar hela JSON-objektet som skickats till dem kan det vara mer effektivt att använda JSON-funktioner på mindre JSON-objekt inuti en loop som upprepas många gånger.

Kopiera
Ange variabel [ $Produktlista ; Värde: JSONListValues ( $$JSON ; "bageri.produkt" ) ]
Ange variabel [ $ProduktAntal ; Värde: ValueCount ( $Produktlista ) ]
Ange variabel [ $i; Värde: 1 ]
If [ $ProduktAntal > 0 ]
   Loop [ Rensa: Alltid ]
      Ny post/sökpost
      Ange variabel [ $Produkt ; Värde: GetValue ( $Produktlista ; $i ) ]
      Tilldela fält [ Produkter::ID ; JSONGetElement ( $Produkt ; "id" ) ]
      Tilldela fält [ Produkter::Pris ; JSONGetElement ( $Produkt ; "pris" ) ]
      Tilldela fält [ Produkter::Lager ; JSONGetElement ( $Produkt ; "lager" ) ]
      Verkställ post/sökpost [ Med dialogruta: Av ]
      Ange variabel [ $i ; Värde: $i + 1 ] 
      Exit Loop If [ $i > $ProduktAntal]
   End Loop
End If

Ändra och lägga till JSON-dataelement

Ändra värden och lägg till element i JSON-data med hjälp av Funktionen JSONSetElement. Parametrarna json och nyckelEllerIndexEllerSökväg arbetar i den här funktionen enligt beskrivningen i Tolka JSON-data. Om nyckelEllerIndexEllerSökväg anger ett befintligt element ändras värdet för det elementet; om elementet inte finns läggs ett nytt element till.

JSONSetElement anger det specificerade elementet till värde-parametern. Vilka giltiga JSON-värden som helst kan anges, från enkla strängar eller tal till komplicerade objekt eller matriser.

Parametern typ anger typen av data i värde så att JSON-tolkaren följer strikta regler vid hantering av varje datatyp. Information om vilka datatyper som stöds finns i Funktionen JSONSetElement. För att infoga data i json som redan är formaterad som ett giltigt JSON-element, anger du JSONRaw som typ.

Följande exempel lägger till nyckelvärdesparen för en ny produkt till ett tomt JSON-objekt. Det nya objektet läggs till i slutet av produktmatrisen i $$JSON-variabeln (mer information finns i Exempel på JSON-data).

Kopiera
Ange variabel [ $NyProdukt ; Värde: 
   JSONSetElement ( "{}" ;
      [ "id" ; "FB4" ; JSONString ] ; 
      [ "namn" ; "Vaniljtårta" ; JSONString ] ; 
      [ "pris" ; 17.5 ; JSONNumber ] ; 
      [ "lager" ; 12 ; JSONNumber ] ; 
      [ "kategori" ; "Tårtor" ; JSONString ] ; 
      [ "special" ; true ; JSONBoolean ] 
   ) ]
Ange variabel [ $NästaIndex ; Värde: 
   ValueCount ( 
      JSONListKeys ( $$JSON ; "bageri.produkt" ) 
   ) ] 
Ange variabel [ $$JSON ; Värde: 
   JSONSetElement ( 
      $$JSON ; "bageri.produkt[" & $NästaIndex & "]" ; $NyProdukt ; 
      JSONObject 
   ) ]

En annan JSON-funktion som skapar ett JSON-element är Funktionen JSONMakeArray. Den gör om en lista med värden till en JSON-matris. Om du vill kunna hantera data som formaterats på olika sätt kan du med den här funktionen ange det tecken som separerar de olika värdena och vilken JSON-datatyp som ska användas.

Ta bort JSON-dataelement

Radera ett element med hjälp av Funktionen JSONDeleteElement. Parametrarna json och nyckelEllerIndexEllerSökväg arbetar i den här funktionen enligt beskrivningen i Tolka JSON-data. Parametern nyckelEllerIndexEllerSökväg måste ange ett befintligt element i json.

Följande exempel tar bort elementet i den produktmatris vars "id-nyckel" har värdet "FB3" i $$JSON-variabeln (mer information finns i Exempel på JSON-data).

Kopiera
Ange variabel [ $ProduktAntal ; Värde: 
   ValueCount ( 
      JSONListKeys ( $$JSON ; "bageri.produkt" ) 
   ) ] 
Ange variabel [ $i ; Värde: 0 ]
If [ $ProduktAntal > 0 ]
   Loop [ Rensa: Alltid ]
      Ange variabel [ $ID ; Värde: 
         JSONGetElement ( $$JSON ; "bageri.produkt[" & $i & "]id" ) ]
      If [ $ID = "FB3" ]
         Ange variabel [ $$JSON ; Värde: 
            JSONDeleteElement ( $$JSON ; "bageri.produkt[" & $i & "]" ) ]
         Avsluta script [ Textresultat: 0 ]
      End If
      Ange variabel [ $i ; Värde: $i + 1 ]
      Exit Loop If [ $i ≥ $ProduktAntal ]
   End Loop
End If

Optimera JSON-prestanda

När en JSON-funktion parsar eller tolkar textindata skapar JSON-parsern en binär representation (inte text) av den så att senare bearbetning av JSON går snabbare. Det finns en automatisk mekanism för att parsa och cachelagra JSON och en explicit: Funktionen JSONParse.

Använda automatisk JSON-cachelagring

Parsning tar tid, så JSON-funktionerna cachelagrar den binära representationen av senast parsade JSON i minnet. Det minskar behovet av att parsa samma JSON igen senare. Endast en automatisk cache upprätthålls. När ett annat JSON-värde parsas, ersätts det tidigare cachelagrade JSON-värdet. Det parsade JSON finns bara i minnet – i variabler, scriptparametrar och beräkningar. När det används för att ange ett fälts värde lagras det i fältet som text.

Med radnummer illustrerar detta exempel när JSON-texten som ursprungligen lagras i $JSON1 och $JSON2 parsas och när den inte gör det.

Kopiera
Ange variabel [ $id ; JSONGetElement ( $JSON1 ; "id" ) ]
Ange variabel [ $namn ; JSONGetElement ( $JSON1 ; "namn" ) ]
Ange variabel [ $pris ; JSONGetElement ( $JSON2 ; "pris" ) ]
Ange variabel [ $kategori ; JSONGetElement ( $JSON1 ; "kategori" ) ]
  1. $JSON1 parsas och den binära representationen sparas i cachen.

  2. $JSON1 behöver inte parsas igen.

  3. $JSON2 parsas och cachelagras, vilket ersätter det tidigare cachelagrade värdet.

  4. $JSON1 parsas igen eftersom det inte längre cachelagrades.

Så för att dra nytta av automatisk cachelagring är det bäst att arbeta med ett JSON-värde åt gången (i exemplet ovan skulle rad 3 och 4 byta plats för att undvika att parsa $ JSON1 igen).

Använda JSONParse

Använd Funktionen JSONParse för att parsa och uttryckligen lagra den binära representationen av ett JSON-värde i en variabel såväl som i den automatiska cachen. Funktionens parameter json är ett textuttryck som utvärderas till JSON-data, oavsett om det är text formaterad som JSON i ett fält eller en sträng, eller redan parsad JSON i en variabel.

Följande exempel parsar JSON-text:

Kopiera
Ange variabel [ $JSON1 ; "{ \"produkt\": {\"id\": \"FB1\"} }" ]
Ange variabel [ $JSON1 ; JSONParse ( $JSON1 ) ]
  1. $JSON1 är bara textrepresentationen, som ser ut så här:

    { "produkt": {"id": "FB1"} }

  2. Efter användning av JSONParse gäller följande:

    • Den automatiska cachen innehåller den binära representationen.

    • Variabeln $JSON1 innehåller både textrepresentation och binär representation.

Om JSONParse inte används i det här exemplet:

Kopiera
Ange variabel [ $JSON1 ; "{ \"produkt\": {\"id\": \"FB1\"} }" ]
Ange variabel [ $JSON2 ; JSONGetElement ( $JSON1 ; "produkt") ]
  1. Då är $JSON1 bara textrepresentationen, som tidigare.

  2. Efter användning av JSONGetElement:

    • Den automatiska cachen innehåller den binära representationen.

    • $JSON2 innehåller den binära representationen av {"id": "FB1"}.

    • $JSON1 är fortfarande bara textrepresentationen. Texten har parsats, men den binära representationen finns bara i den automatiska cachen.

Jämför det med vad som händer när du lägger till JSONParse:

Kopiera
Ange variabel [ $JSON1 ; "{ \"produkt\": {\"id\": \"FB1\"} }" ]
Ange variabel [ $JSON1 ; JSONParse ( $JSON1 ) ]
Ange variabel [ $JSON2 ; JSONGetElement ( $JSON1 ; "produkt") ]
  1. Då är $JSON1 bara textrepresentationen, som tidigare.

  2. Efter användning av JSONParse gäller följande:

    • Den automatiska cachen innehåller den binära representationen.

    • $JSON1 innehåller både textrepresentation och binär representation.

  3. Efter användning av JSONGetElement:

    • $JSON2 innehåller den binära representationen av {"id": "FB1"}.

      Textrepresentation lagras inte i $JSON2 vid denna tidpunkt men genereras senare först när det behövs.

Observera att JSONGetElement inte behövde parsa $ JSON1 på rad 3, eftersom den kunde använda den binära representationen som cachelagrats med $ JSON1 på rad 2.

Precis som det tar tid att parsa text för att få en binär representation så tar det också tid att konvertera binär JSON till text. Det är därför resultatet av JSON-funktioner som JSONGetElement och JSONSetElement endast är den binära representationen. Textrepresentationen skapas först när den behövs, till exempel när du lagrar en variabel (till exempel $JSON2) i ett fält, eller när du visar en variabel i Datagranskaren.

Du kan använda funktionen JSONParsedState för att ta reda på om ett givet JSON-värde har parsat JSON lagrat med det, om JSON är giltigt och vilken JSON-typ det är.

Bästa praxis

Vid bearbetning av stora JSON-strukturer upprepade gånger (särskilt i loopar) eller arbete med flera element i JSON-data kan arbetsordningen göra en betydande skillnad i prestanda.

För att dra nytta av automatisk JSON-cachelagring är det bäst att inte växla mellan att läsa in JSON-data från ett fält att arbeta med, växla till ett annat fält att arbeta med och gå sedan tillbaka till det första fältet. Varje gång en JSON-funktion bearbetar olika JSON-text, kasseras den tidigare cachade JSON, så texten måste parsas igen. Det här ger till exempel den långsammaste prestandan:

Kopiera
# Exempel – Ej effektivt
Ange variabel [ $namnl ; Värde: JSONGetElement ( Tabell::JSON1 ; "namn" ) ]
Ange variabel [ $namn2 ; Värde: JSONGetElement ( Tabell::JSON2 ; "namn" ) ]
Ange variabel [ $id1 ; Värde: JSONGetElement ( Tabell::JSON1 ; "id" ) ]
Ange variabel [ $id2 ; Värde: JSONGetElement ( Tabell::JSON2 ; "id" ) ]

Genom att bara ändra ordningen på stegen så att du gör allt arbete med samma JSON-data innan du arbetar med andra JSON-data, fungerar den automatiska cachen till din fördel, vilket eliminerar behovet av att parsa data från samma fält två gånger.

Kopiera
# Exempel - Bättre
Ange variabel [ $namel ; Värde: JSONGetElement ( Tabell::JSON1 ; "namn" ) ]
Ange variabel [ $id1 ; Värde: JSONGetElement ( Tabell::JSON1 ; "id" ) ]
Ange variabel [ $name2 ; Värde: JSONGetElement ( Tabell::JSON2 ; "namn" ) ]
Ange variabel [ $id2 ; Värde: JSONGetElement ( Tabell::JSON2 ; "id" ) ]

Den bästa, mest flexibla metoden är att använda funktionen JSONParse för att hämta JSON-texten från varje källa, parsa den och lagra den i en variabel. På så sätt parsas den bara en gång. Då spelar det ingen roll i vilken ordning du gör ytterligare operationer (som att hämta eller ange element) eftersom de JSON-funktionerna kan använda variablerna, som innehåller de redan parsade binära representationerna.

Kopiera
# Exempel - Bäst
Ange variabel [ $JSON1 ; Värde: JSONParse ( Tabell::JSON1 ) ]
Ange variabel [ $JSON2 ; Värde: JSONParse ( Tabell::JSON2 ) ]

Ange variabel [ $namnl ; Värde: JSONGetElement ( $JSON1 ; "namn" ) ]
Ange variabel [ $namn2 ; Värde: JSONGetElement ( $JSON2 ; "namn" ) ] 
Ange variabel [ $id1 ; Värde: JSONGetElement ( $JSON1 ; "id" ) ]
Ange variabel [ $id2 ; Värde: JSONGetElement ( $JSON2 ; "id" ) ]

Hantera fel i JSON-data

Om det uppstår ett fel när json-parametern tolkas returnerar JSON-funktionerna "?" följt av ett felmeddelande från JSON-tolken.

Till exempel, när ":" efter "bageri" saknas i Exempel på JSON-data, returnerar den här beräkningen

Kopiera
JSONGetElement ( $$JSON ; "bageri.produkt[0]id" )

följande felmeddelande:

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

Du kan bedöma om JSON-data är giltiga innan du använder dem genom att använda Funktionen JSONFormatElements och testa om det första tecknet är "?". Till exempel:

Kopiera
Ange variabel [ $resultat ; Värde: JSONFormatElements ( $$JSON ) ]
If [ Left ( $result ; 1 ) = "?" ]
   # $$JSON innehåller ogiltiga JSON-data.
End If

Alternativt kan du använda Funktionen JSONGetElementType för att avgöra om JSON-data är giltiga och av en specifik JSON-typ innan du använder dem. Om du till exempel vill testa om $$JSON är ett giltigt JSON-objekt:

Kopiera
Ange variabel [ $resultat ; Värde: JSONGetElementType( $$JSON, "" ) ]
If [ $result ≠ JSONObject ]
    # $$JSON innehåller ogiltiga JSON-data
End If

Ett annat sätt att upptäcka fel är med Funktionen JSONParsedState. Den kan berätta om JSON-data har parsats och är giltiga, och i så fall vilken typ av JSON-data det är.

Kopiera
Ange variabel [ $resultat ; Värde: JSONParse ( $$JSON ) ]
Ange variabel [ $ParsadStatus ; Värde: JSONParsedState ( $resultat ) ]
If [ $ParsadStatus < 0 ]
    # $$JSON har parsats men innehåller ogiltiga JSON-data.
Else If [ $ParsadStatus = 0 ]
    # $$JSON har inte parsats.
Else If [ $ParsadStatus > 0 ]
    # $$JSON har parsats och är giltig. $ParsadStatus indikerar JSON-typ.
    Ange variabel [ $typ ; Värde: 
        Case ( 
          $ParsadStatus = JSONString ; "JSON-typ är JSONString" ;
          $ParsadStatus = JSONNumber ; "JSON-typ är JSONNumber" ;
          $ParsadStatus = JSONObject ; "JSON-typ är JSONObject" ;
          $ParsadStatus = JSONArray ; "JSON-typ är JSONArray" ;
          $ParsadStatus = JSONBoolean ; "JSON-typ är JSONBoolean" ;
          $ParsadStatus = JSONNull ; "JSON-typ är JSONNull"
        )
    ]
    Visa anpassad dialogruta [ $typ ]
End If

Exempel på JSON-data

Följande exempel på JSON-data innehåller ett "bageriobjekt" som har en matris av tre produktobjekt, vart och ett med flera nyckelvärdespar.

Kopiera
{
    "bageri"
    {
        "produkt"
        [
            {
                "id" : "FB1",
                "namn" : "Munkar",
                "pris" : 1.99,
                "lager" : 43,
                "kategori" : "Bröd",
                "special" : true
            },
            {
                "id" : "FB2",
                "pris" : 22.5,
                "namn" : "Chokladtårta",
                "lager" : 23,
                "kategori" : "Tårtor"
                "special" : true
            },
            {
                "id" : "FB3",
                "pris" : 3.95,
                "namn" : "Baguette",
                "lager" : 34,
                "kategori" : "Bröd"
                "special" : true
            }
        ]
    }
}

Kommentarer 

  • JSON-tolkaren bevarar ordningen på elementen i en matris, men inte ordningen på elementen i ett objekt. JSON-funktioner kan därför returnera element i ett objekt i en annan ordning än den angivna.

  • I JSON-data måste numeriska bråktal använda punkt "." som decimaltecken oavsett vilket tecken som anges av datorns systemformat eller de format som användes när FileMaker Pro-filen skapades.