JSON: chopping and changing


rein in die Kartoffeln, raus aus den Kartoffeln

Ich will zwei Datensätze aus der gleichen Tabelle in einem Formular anzeigen. Den einen Datensatz im Master-Formular, den anderen in einer Subform. Die Subform bekommt über die ihr zugewiesene Variable den Datensatzinhalt geliefert, wie hier beschrieben.

In Vorbereitung des Datenaustausches verpacke ich den Datensatz mit den Verbrauchsdaten als JSON und speichere das JSON im Datensatz mit ab. Über SQL lade ich den Datensatz. So bleibt der bereits geladene Datensatz unangetastet und der Inhalt des neuen Datensatz wird als JSON übergeben. *

Statt jedesmal neu zu verpacken, verpacke ich beim Sichern die Felder in JSON und hebe das JSON im Datensatz aus. Das ist simpler und Plattenplatz ist billig. Das JSON wird später in Variablen entpackt.

Verpacken habe ich so gelöst:

  • über alle Felder eine For-Schleife
  • den Feldnamen als Key verwenden
  • den Feldinhalt über OB Set einsetzen und 4D die Typenwandlung überlassen
  • in Zeile 6 nehme ich das Zielfeld aus. Macht keinen Sinn, sich selber in sich selber zu schreiben
  • in Zeile 13 erzeuge ich aus dem JSON-Object einen Text, um nicht auf den Datentyp Object, sprich V15, angewiesen zu sein

1 $table_L:=Table(->[VERBRAEUCHE])
2 $N:=Get last field number($table_L)
3 For ($i;1;$N)
4 If (Is field number valid($table_L;$i))
5 $P_Field:=Field($table_L;$i)
6 If ($P_Field=(->[VERBRAEUCHE]VBRCH_Record_JSON))
7 Else
8 $fieldName:=Field name($table_L;$i)
9 OB SET($record_O;$fieldName;$P_Field->)
10 End if
11 End if
12 End for
13 [VERBRAEUCHE]VBRCH_Record_JSON:=JSON Stringify($record_O)
14 CLEAR VARIABLE($record_O)

Ausgepackt wird in dieses als Subform konzipierte Formular. Es gibt nur Form-Variablen und die Variablen haben als Objektnamen den Feldnamen, den sie darstellen sollen.

SubFormVerbrauch

Dazu diese Auspackmethode:

  • alle Keys in ein Array laden, das enthält dann die Feldnamen und damit den Objektnamen der Variablen
  • über alle Keys in einer Schleife erzeuge ich einen Pointer auf das Variablen-Objekt
  • ist der Pointer auf das benannte Objekt Nil, weiter zum nächsten Feld, sonst
  • hole ich mir mit OB Get den Wert und überlassen 4D die Typenwandlung
  • Zeile 9 und 10 nur, um den forcierten Datentyp zu testen

1 ARRAY TEXT($t_Key;0)
2 ARRAY LONGINT($t_Types_L;0)
3 OB GET PROPERTY NAMES($P_boundObj->;$t_Key;$t_Types_L)
4 $N:=Size of array($t_Key)
5 For ($i;1;$N)
6 $P_Object:=OBJECT Get pointer(Object named;$t_Key{$i})
7 Case of
8 : (Nil($P_Object))
9 : ($t_Key{$i}=Field name(->[VERBRAEUCHE]VBRCH_AbleseTag_D))
10 $P_Object->:=OB Get($P_boundObj->;$t_Key{$i};Is date)
11 Else
12 $P_Object->:=OB Get($P_boundObj->;$t_Key{$i})
13 End case
14 End for

In der Anwendung wird die Subform mit dem Dateninhalt über einem Datenpunkt im SVG angezeigt. Dazu lese ich die ID des SVG-Elementes aus, suche den Datensatz, übergebe an die Subform den Datensatz als JSON-Objekt und bewege die Subform über den Datenpunkt und setze sie sichtbar. Das Entpacken wird durch On bound variable change getriggered.

Gas_Layout_klein

 



chopping and changing

I need to display two different records inside one form. One as part of the main-form, the other one inside the subform. The subform gets the record data by altering the subform-variable’s content, as shown here.

Instead of packing on the fly, I’m going to pack the record-content into JSON when saving and store that JSON as field. Only reason: that way of working makes things easier and diskspace is cheap. The record will be retrieved by a line of SQL-code * and unpacked into variables.

Packing works like this:

  • a for-loop across all fields
  • fieldname will be key
  • OB Set sets the value to the field’s content, 4D doing the type conversion
  • row 6 explicitly omits the target field. Makes no sense, storing itself into itself
  • row 13 converts JSON into string, to avoid being dependent on V15

1 $table_L:=Table(->[VERBRAEUCHE])
2 $N:=Get last field number($table_L)
3 For ($i;1;$N)
4 If (Is field number valid($table_L;$i))
5 $P_Field:=Field($table_L;$i)
6 If ($P_Field=(->[VERBRAEUCHE]VBRCH_Record_JSON))
7 Else
8 $fieldName:=Field name($table_L;$i)
9 OB SET($record_O;$fieldName;$P_Field->)
10 End if
11 End if
12 End for
13 [VERBRAEUCHE]VBRCH_Record_JSON:=JSON Stringify($record_O)
14 CLEAR VARIABLE($record_O)

Unpacking is aimed at this form which is a subform conceptually. There are form-variables only. Their objectname is identical to the fieldname, they’ll display.

SubFormVerbrauch

This is unpacking:

  • put all keys into an array, keynote was fieldname, now it’s the variable’s object name
  • create a pointer for all keys, which means a pointer to a variable with appropriate object name
  • if that object-pointer is nil, then there is no variable, next
  • moving value into variable is done by OB Get, 4D doing the typeconversion
  • rows 9 and 10 demonstrate forced typeconversion

1 ARRAY TEXT($t_Key;0)
2 ARRAY LONGINT($t_Types_L;0)
3 OB GET PROPERTY NAMES($P_boundObj->;$t_Key;$t_Types_L)
4 $N:=Size of array($t_Key)
5 For ($i;1;$N)
6 $P_Object:=OBJECT Get pointer(Object named;$t_Key{$i})
7 Case of
8 : (Nil($P_Object))
9 : ($t_Key{$i}=Field name(->[VERBRAEUCHE]VBRCH_AbleseTag_D))
10 $P_Object->:=OB Get($P_boundObj->;$t_Key{$i};Is date)
11 Else
12 $P_Object->:=OB Get($P_boundObj->;$t_Key{$i})
13 End case
14 End for

The application displays the subform on top of a SVG-picture-object. Moving the cursor over the SVG, reads the ID of the SVG-element, queries the record, and sets the subform-variable to the JSON-object, sets the subform visible and moves it atop the datapoint. On bound variable change triggers unpacking.

Gas_Layout_klein


* simple SQL-code applied
1 Begin SQL
2 Select VBRCH_Record_JSON from VERBRAEUCHE where VBRCH_Key_L = :$longintPara_L into :$jsonText
3 End SQL