HTML Formular Input Daten besser strukturieren

Wie mit Markup eine zweckmäßige Datenstruktur erzeugt werden kann welche den Content-Type für die zu sendenden Daten bestimmt

Diesem Artikel liegt die Idee zugrunde, eine per HTML-Auszeichnung vorgenommene Gruppierung auf einen proprietären Content-Type abzubilden welcher eine dementsprechende Datentruktur transportiert. Hierzu werden Eingabefelder im HTML-Element fieldset gruppiert. Die mit den Eingaben erzeugte Datenstruktur ist ein JS-Objekt welches mehrere Unterobjekte speichert. Zur Übertragung werden diese Objekte serialisiert via POST gesendet mit dem dazugehörigen Content-Type eav/binary. Dieser Content-Type Header ist wichtig, damit der serverseitige Parser den dazu passenden De-Serializer finden und damit die Daten in ihrer Originalstruktur wiederherstellen kann.

Legacy und Default Enctype

Der Default Enctype eines HTML-Formulars lautet Enctype="application/x-www-form-urlencoded" wobei dies wohl selten so notiert wird weil es eben der Default ist. In der Übertragung sehen damit die Daten beispielsweise so aus:

insert=1;colors=red;colors=green;colors=blue;lastname=Otto;firstname=Hans

Womit sich zwangsläufig untenstehende Datenstruktur ergibt:

input = {
    'insert': '1',
    'colors': ['red','green','blue'],
    'lastname': 'Otto',
    'firstname': 'Hans'
};

Nun, einer solchen Datenstruktur haftet der Nachteil an, daß die Daten ihrer Zweckbestimmung nach nicht sonderlich strukturiert sind. So löst z.B. der Parameter insert eine bestimmte Aktion auf dem Zielsystem aus und möglicherweise sollen die übermittelten Farben in eine andere Tabelle als die Personendaten.

Die neue Datenstruktur beginnt mit HTML

Zum Gruppieren gibt es das Fieldset-Element womit die Semantik bereits im Formular zum Ausdruck kommt:

<fieldset id="colors"> <legend>Farben zur Auswahl:</legend>
    <label>Rot:  <input name="colors" type="checkbox" value="red">   </label>
    <label>Grün: <input name="colors" type="checkbox" value="green"> </label>
    <label>Blau: <input name="colors" type="checkbox" value="blue">  </label>
</fieldset>
Farben zur Auswahl:

Nun würde man, um in dem Beispiel zu bleiben, für die Personendaten eine weiteres Fieldset anlegen;

<fieldset id="person"> <legend class="legend">Angaben zur Person:</legend>
    <label>Vorname:  <input style="width:100%" name="person.firstname" value="Hans"> </label>
    <label>Nachname: <input style="width:100%" name="person.lastname" value="Otto">  </label>
</fieldset>
Angaben zur Person:

Und schließlich eine Schaltfläche auszeichnen mit welcher der Benutzer das Senden aller getätigten Eingaben zum Server veranlasst.

<button type="button" name="insert" onclick="insert()" class="put_button">Daten zum Server senden</button>

Mit einem Klick auf untenstehende Schaltfläche wird nun ein Ajax-Request die Daten senden und die Response die Datenstruktur zeigen die am Server angekommen ist:

Hinweis: Wenn sich der Cursor in einem der Textfelder befindet, löst die Entertaste ein Submit aus. Auch in diesem Fall wird aus den Parametern dieselbe Datenstruktur erzeugt, allerdings erst serverseitig. Diese wird als Dump im Browser ausgegeben.

Eine zweckmäßigere Datenstruktur

In der Praxis hat es sich immer wieder als zweckmäßig erwiesen, Schlüssel~ bzw. Actionparameter von den Nutzdaten zu trennen. Eine diesem Prinzip entsprechende Datensruktur könnte beispielsweise so aussehen wie auch die Response weiter oben zeigt:

input = {
    param: {
        insert: '1'
    },
    person: {
        firstname: 'Otto',
        lastname: 'Hans'
    },
    colors: {
        0: 'red',
        1: 'green',
        2: 'blue'
    }
};

Clientseitig sind, dem Beispiel folgend, den der Gruppierung dienenden Fieldset-Elementen die ID's colors und person zugewiesen. Damit ist über den document.querySelectorAll recht einfach möglich, die Werte sämtlicher darunterliegender Eingabefelder auszulesen

Erläuterungen zur serverseitigen Technik

Zuerst bekommt der Serverseitige Parser einen neuen Layer, wird also erweitert um den hinzugekommenen Content-Type:

# Codestück im serverseitigen Parser
# Schlüsselparameter im Hash param
# Nutzdaten in eav
# der den Content-Type entsprechende Layer
# EAVHandle.pm wird eingebunden
elsif( $self->{CONTENT_TYPE} eq 'eav/binary' ){
    require EAVHandle;
    $self->{eav} = EAVHandle->handle2eav( $self->{STDIN} );
    $self->{param} = $self->{eav}->{param};
}

Mit dieser Erweiterung ist es nun möglich, den zum URL gehörigen Controller (Framework MVC) um die beabsichtigte Action zu erweitern. Die der Frameworkinstanz gehörende Methode param() wird wie bisher angewandt, ein hinzugekommener Content-Type ändert also daran nichts:

elsif( $self->param('insert') ){
    $self->dd( $self->{CGI}->eav );
}

D.h., für die Demo wird hier nur ein Dump erzeugt. Der Dump zeigt die empfangenen Daten in der beabsichtigten Struktur also wie darauf zugegriffen werden kann. File-Uploads sind mit dem hier gezeigten Content-Type natürlich auch ganz einfach zu realisieren. Sofern keine Uploads zu realisieren sind, kann dieselbe Datenstruktur selbstverstänlich auch als JSON serialisiert werden. In der serverseitigen Parameter-Kontrollstruktur sind hierzu keine Änderungen notwendig weil der Parser diesen Content-Type bereits kennt und automatisch den dazugehörigen Code für diesen Layer einbindet.

Kompatibilitätsmodus

Sofern kein JavaScript verfügbar ist, greift eine über die Feldnamen erzwungene Strukturierung über dem Legacy-Enctype. Obenstehendes Formular funktioniert also auch, wenn Sie den Fokus auf eines der Inputfelder setzen und die Entertaste betätigen.

Hierbei werden die Daten über die Namen der Inputfelder strukturiert. Feldnamen wie:

person.firstname
person.lastname

Sind also in zwei Teile aufgesplittet wobei der erste Teil vor dem Punkt die Gruppenzugehörigkeit ausweist. Der Teil nach dem Punkt ist der eigentliche Feldname für das jeweilige Eingabefeld.


Die rein persönlichen Zwecken dienende Seite verwendet funktionsbedingt einen Session-Cookie. Datenschutzerklärung: Auf den für diese Domäne installierten Seiten werden grundsätzlich keine personenbezogenen Daten erhoben. Das Loggen der Zugriffe mit Ihrer Remote Adresse erfolgt beim Provider soweit das technisch erforderlich ist. @: Rolf Rost, Am Stadtgaben 27, 55276 Oppenheim, nmq​rstx-18­@yahoo.de