Möglichkeiten zum Einbau einer AJAX-Response in das DOM

Zur Übertragung und zum Einbau einzelner Werte aus der AJAX-Response in das HTML-Dokument gibt es verschiedene Möglichkeiten

Einzelwerte in einer Response

Im einfachsten Fall wird in einer AJAX-Response bzw. im Response-Message-Body nur ein einzelner Wert übertragen. Über sogenannte Selektoren (TagName, Id, class) wird dieser Wert dann in das gewünschte DOM Element eingebaut, Beispiel:

    document.getElementById('name').value = response;

Wobei sich dieser Vorgang stets innerhalb der für den Request zuständigen Callback-Funktion abspielt. Genausogut jedoch kann ein einzelner Wert in einem Custom-Response-Header übertragen werden:

    document.getElementById('name').value =
        xhr.getResponseHeader('x-name');

Hierbei ist jedoch zu beachten, dass ein HTTP-Header nur ASCII enthalten darf, während in einem Message-Body Bytes (Oktetten) beliebiger Wertigkeiten zulässig sind. In Fakt kann ein Message-Body eine native Binary enthalten, wie zum Beispiel eine Audio-, Video- oder Grafikdatei. Und zum Escapen/Encoden von Werten mit dem Ziel, dass diese nur noch ASCII sind, gibt es auch entsprechende Möglchkeiten wie z.B. das Percent-Encoding (Prozentkodierung).

Über die zulässige Länge eines Custom-Headers habe ich verschiedene Angaben gefunden bis zu 8 kByte, was den meisten Anforderungen wohl genügen sollte. Soll die Übertragung einzelner oder mehrer Werte lediglich per Response-Header erfolgen, reicht ein HEAD-Request und mehrere Werte werden auf mehrere Custom-Header aufgeteilt. In der Callbackfunktion werden die entsprechenden Header einfach direkt abgefragt:

    document.getElementById('lastname').value  =
        decodeURIComponent(xhr.getResponseHeader('x-lastname'));
    document.getElementById('firstname').value =
        decodeURIComponent(xhr.getResponseHeader('x-firstname'));

Das Beispiel zeigt auch, wie die Prozentkodirung wieder rückgängig gemacht werden kann unter Anwendung der Funktion decodeURIComponent(). Schließlich können mehrere Schlüssel-Werte-Paare auch in einem einzigen String zusammengefasst werden wie das bei einem HTTP-QUERY_STRING üblich ist.

XML oder JSON für mehrere Werte

Die Frage wird oft gestellt, ist im Grunde genommen jedoch unsinnig weil es außer diesen beiden Möglichkeiten ungezählte weitere Möglichkeiten zum Serialisieren von Datenstrukturen gibt. Wer eine XML-Response verarbeiten möchte, schaue sich den XSLTProcessor an, ich werde hier aber nicht weiter darauf eingehen. Interessante Möglichkeiten jedoch ergeben sich, wenn die XML-Response so geparst wird, dass ein eigenes Objekt entsteht: Für den wahlfreien Zugrif auf einzelne Werte. Letzteres ist auch das Ziel einer Übertragung der Response als JSON-String.

Die Wichtigste, in der Callbackfunktion aus dem Message-Body der Response zu regenerierende Datenstruktur ist ein Objekt bzw. ein Array mit Objekten, abstrakt sieht das so aus: [{},{},{},{}] hierbei sind die einzelnen Objekte über den Index ansprechbar. Ob eine solche Struktur, die direkt einer Templating-Engine übergeben werden kann, per JSON oder anderweitig serialisiert wurde, ist technisch belanglos und nur eine Frage der Verfügbarkeit der entsprechenden Blibliotheken.

Templating Engines in JavaScript oder serverseitig

Ziel ist es, die in der Response gesendeten Einzelwerte dem Wunsch entsprechend im DOM zu platzieren. Infolgedessen, dass Bestimmungsorte für Einzelwerte nicht per Id, TagName oder anderen Selektoren ermittelt wird, gestaltet sich der Einbau über Platzhalter recht einfach. Auf diese Art und Weise lassen sich ganze Bäume manipulieren, nur noch das Wurzelelement muss selektiert werden um den Baum an der entsprechenden Stelle einpflanzen zu können.

Andererseits lässt sich ein aus HTML-Elementen bestehender Baum auch serverseitig fix und fertig über ein Template mit Werten bestücken, in diesem Fall werden keine Objekte serialisiert sondern nur nuch ein einziger Wert übertragen: Ein gerendertes Template als String.

Serializer für einen Slice like [{},{},{},{}...]

Wie bereits angemerkt, JSON ist nicht alles. Im Folgenden beschreibe ich einen Algorithmus der 3x performanter als JSON arbeitet, was sich bei größeren Datenmengen bemerkbar macht. Untenstehend der CODE in Perl und JavaScript:

# Perl
package SliceHash;

use strict;
use warnings;

sub _escape{
    my $s = shift || '';
    $s =~ s/%/%25/g;  # das Prozentzeichen selbst
    $s =~ s/&/%26/g;  # trennt die Slices
    $s =~ s/;/%3B/g;  # trent die Schlüssel-Werte Paare
    $s =~ s/\=/%3D/g; # Feld-Trenner
    return $s;
}

sub _unescape{
    my $s = shift || '';
    $s =~ s/%26/&/g;
    $s =~ s/%3B/;/g;
    $s =~ s/%3D/\=/g;
    $s =~ s/%25/%/g;
    return $s;
}

sub decode{
    my $pkg = shift;
    my $s   = shift;
    my @slices = split "&", $s;
    my @out = ();
    foreach my $s(@slices){
        push @out, do{
            my @slicestr = split ";", $s;
            my @h = map { split "=", $_, 2} @slicestr;
            my %has = ();
            while(my $k = shift @h){
                $has{$k} = sprintf("%s", _unescape(shift @h));
            }
            \%has;
        };
    }
    \@out;
}

sub encode{
    my $pkg = shift;
    my $r   = shift; # [{},{},{},{}]

    my @out = ();
    foreach my $h(@$r){
        push @out, do{
            my @av = map { sprintf("%s=%s", $_, _escape($h->{$_})) } keys %$h;
            join ";", @av;
        };
    }
    return join "&", @out;
}
1;

// JavaScript
/* Slice decode -- Passend zum Template */
function slice_decode(s){
    var slices = s.split("&");
    var out = [];
    for(var i = 0; i < slices.length; i++){
        var pairs = slices[i].split(";");
        var obj = {};
        for(var ii = 0; ii < pairs.length; ii++){
            var[att, val] = pairs[ii].split("=");
            obj[att] = decodeURIComponent(val);
        }
        out.push(obj);
    }
    return out;
}

Zum Verständnis der Funktionsweise: Die inneren Objekte sind Schlüssel-Werte-Paare, in der erzeugten Sequenz steht das =Zeichen zwischen Schlüssel und Wert. Das Semikolon ; trennt dann die einzelnen Schlüssel-Werte-Paare und schließlich trennt das Ampersand (Kaufmannsund) & die einzelnen Objekte voneinander. Des Weiteren sorgt die Prozentkodierung dafür, dass diese zum Strukturieren benutzten Zeichen & = ; im Wert selbst maskiert sind. Die Javascript-Funktion decodeURIComponent() macht diese Kodierung wieder rückgängig.


Datenschutzerklärung: Diese Seite dient rein privaten Zwecken. 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. s​os­@rolf­rost.de.