#Klooienmetcomputers

Werken met JSON

Arnout van Kempen over rommelen in een digitale wereld.

De vorige keer hebben we onze eigen AI gebouwd, maar daar bleef een lastige kwestie onbeantwoord: Hoe sla je de gegevens uit een binaire dynamisch gealloceerde node-structuur op in een bestand?

Bij een array van kenniselementen zou het makkelijk zijn, die schrijf je gewoon zo weg. En ook bij een linked list waarvan je de omvang niet kent is het niet zo moeilijk. Gewoon vanaf de root-node de data naar je bestand schrijven, door naar de volgende node en dat herhalen tot je pointer naar NULL wijst. Terug opbouwen vanuit het bestand gaat hetzelfde: data lezen, node vullen, child node maken en met pointer verbinden, tot de laatste gelezen is, dan afsluiten met een NULL en je bent er.

Maar wat moet je met een boomstructuur, waarbij je niet weet hoeveel vertakkingen er zijn en hoe groot die zijn? In het voorbeeld van de vorige keer weet je wel een paar dingen zeker:

  1. 1.Iedere VRAAG-node heeft twee child nodes: een met een ja-pointer en een met een nee-pointer.
  2. 2.Iedere DING-node heeft nul child nodes en dus twee NULL pointers naar ja en nee.

Je zou deze kunnen opslaan, en opnieuw opbouwen, via een recursieve functie. Deze zou, voor het opslaan, dan ongeveer dit moeten doen:

void slaNodeOp(Node* node)
{
     if(node->type == DING)
          {
               sla de node op;
               return;
          }
     else
          {
               sla de node op;
               slaNodeOp(node->ja);
               slaNodeOp(node->nee);
          }
return;
}

Het idee is dat de functie de node opslaat en dan waar nodig recursief de beide child-nodes opslaat. Deze recursie herhaalt zichzelf totdat een DING wordt bereikt. Op deze manier wordt de hele boom opgeslagen vanaf de eerste node waarmee je de functie aanroept.

Dat is conceptueel mooi, maar hoe doe je dat technisch? C werkt uit zichzelf niet met databases zoals MySQL. Een bestand in C is min of meer standaard een tekstbestand of een binair bestand, dat is in beide gevallen een sequentieel en ongestructureerd bestand. Als je structuur wil aanbrengen zal je dat zelf moeten doen. Maar goed, je moet in C vrijwel alles zelf doen, dus dat is eigenlijk geen verrassing.

Op zich is het ook helemaal niet moeilijk om de kennis-nodes uit ons AI-programma in een bestand te zetten. Als je naar een scherm schrijft gebruik je printf(“tekst en codes”, variabelen) en naar een bestand werkt het vrijwel exact hetzelfde met fprintf(bestand, “tekst en codes”, variabelen). Je zou nodes bijvoorbeeld kunnen wegschrijven met fprintf(bestand, “%s:%s”,(node->type == VRAAG)? “V” : “D”, (node->type == VRAAG)? node->data.vraag : node->data.ding);.

Het probleem is alleen dat alle nodes op zichzelf wel herkenbaar zijn als VRAAG of als DING via de eerste letter, maar dat de relaties tussen de nodes verloren gaan. Op zich zou je je daarover niet druk hoeven te maken, als je de nodes exact hetzelfde uitleest als in de volgorde waarin je ze ook schreef, maar je kan dat niet echt controleren.

Het zou handig zijn als je een soort tussenvorm zou hebben tussen een echte relationele database zoals MySQL die kan leveren en een plat tekstbestand. Daar zijn opties voor beschikbaar. XML, een formaat dat sterk lijkt op HTML dat we kennen van webpagina's, is een bestandsformaat dat heel veel mogelijkheden biedt om meer gestructureerde data op te slaan in een platte tekst. XML is voor accountants helemaal interessant omdat XBRL, de codering voor jaarrekeningen, een specifieke invulling van XML is. XML heeft wel twee nadelen. Ten eerste is het geen onderdeel van standaard C, en ten tweede is het betrekkelijk complex.

Een moderner en eenvoudiger alternatief is JSON (JavaScript Object Notation). Ook dit is een plattetekstbestand, met net als in XML een systeem voor het structureren van data. JSON is echter aanzienlijk eenvoudiger, kent daarmee overigens ook minder mogelijkheden.

De basis van een JSON bestand zijn elementen die tussen {} worden geplaatst, met een label en een inhoud. Een node in ons voorbeeld zou dan zoiets kunnen zijn als { "type" : "VRAAG", "data" : "Is het blauw?"}. Een data-element kan in JSON zelf weer een data-element bevatten. En dat betekent dat je in JSON precies dezelfde structuur kan opbouwen als de boomstructuur die we in ons AI-programma opbouwen.

JSON heeft echter een nadeel dat het deelt met XML: Het is geen onderdeel van standaard C.

Gelukkig is daar natuurlijk wel een oplossing voor. We zagen eerder hoe je je eigen header-files kan maken en toevoegen. Maar je kan natuurlijk ook gebruikmaken van de header-files van anderen. GitHub zit er bijvoorbeeld vol mee. En zo zijn er ook diverse bibliotheken (header+object-files) die functies geven om JSON mee te hanteren. Helaas betekent dat wel dat code niet zonder meer uitwisselbaar is. De functies in cJSON, bijvoorbeeld, doen hetzelfde als die in JSMN wellicht, maar de namen van de functies zijn verschillend, dus code zal aangepast moeten worden aan de bibliotheek die je gebruikt.

Zelf heb ik gekozen voor json-c. Als je die wil gebruiken op een Raspberry Pi zal je die eerst, in de terminal, moeten installeren met sudo apt-get install libjson-c-dev

In je source neem je een #include <json-c/json.h> op, en bij compileren met gcc voeg je de link-bibliotheek toe, met gcc voorbeeld.c -o voorbeeld -ljson-c

Op GitHub heb ik de Makefile hiermee aangepast en heb ik een voorbeeldje, json_test.c , opgenomen.

Let op: Als je werkt met MacOS of MS Windows kan je json-c ook gebruiken, maar zal je de broncode moeten zoeken en zelf compileren.

Wie mee wil doen met #klooienmetcomputers kan dat doen via GitHub. Maak een account op www.github.com en zoek naar Abmvk/kmc. Het account Abmvk volgen kan ook. Lezers zijn vrij te gebruiken wat ze willen en om zelf zaken toe te voegen of aan te passen, vragen te stellen of commentaar te leveren.

Arnout van Kempen di CCO CISA is Senior manager Risk & Compliance bij Baker Tilly. Hij schrijft op persoonlijke titel. Hij is lid van de Commissie Financiële verslaggeving & Accountancy van de AFM en lid van de signaleringsraad van de NBA. Daarnaast is hij diaken van het bisdom 's-Hertogenbosch.

Gerelateerd

reacties

Reageren op een artikel kan tot drie maanden na plaatsing. Reageren op dit artikel is daarom niet meer mogelijk.

Aanmelden nieuwsbrief

Ontvang elke werkdag (maandag t/m vrijdag) de laatste nieuwsberichten, opinies en artikelen in uw mailbox.

Bent u NBA-lid? Dan kunt u zich ook aanmelden via uw ledenprofiel op MijnNBA.nl.