heinetz: String in Array konvertieren

Hallo Forum,

folgendes Konstrukt:

for (var my_item in my_array) {
 ... do something
}

Das funktioniert richtig, solange my_array ein Array ist. Nun kann es aber sein, dass in my_array ein string steht. Ich könnte folgendermassen dafür sorgen, dass my_array in dem Fall zu einem Array mit einem Element konvertiert wird:

if (!Array.isArray(my_array)){
 my_array = [my_array];
}

for (var my_item in my_array) {
 ... do something
}

Allerdings geht das doch sicher auch kürzer resp. eleganter, oder?

gruss, heinetz

  1. Tach!

    Das funktioniert richtig, solange my_array ein Array ist. Nun kann es aber sein, dass in my_array ein string steht. Ich könnte folgendermassen dafür sorgen, dass my_array in dem Fall zu einem Array mit einem Element konvertiert wird:

    if (!Array.isArray(my_array)){
     my_array = [my_array];
    }
    

    Allerdings geht das doch sicher auch kürzer resp. eleganter, oder?

    Was willst du daran noch verkürzen? Funktional muss das so sein, dass die Konvertierung nur stattfindet, wenn es nicht bereits ein Array ist. Es könnte höchstens noch Syntactic Sugar geben, so dass du es kürzer schreiben kannst. Das glaub ich aber nicht, der Wunsch ist recht speziell.

    dedlfix.

  2. Lieber heinetz,

    for (var my_item in my_array) {
     ... do something
    }
    

    willst Du über Objekteigenschaften iterieren? Bei Arrays kann man bequem die forEach-Methode mit callback-Funktion nutzen.

    Das funktioniert richtig, solange my_array ein Array ist. Nun kann es aber sein, dass in my_array ein string steht.

    Auch dann funktioniert es richtig! Mit for in kommst Du auch bei Strings an die Objekteigenschaften heran.

    Ich könnte folgendermassen dafür sorgen, dass my_array in dem Fall zu einem Array mit einem Element konvertiert wird:

    Warum willst Du, dass ein String ein Array ist? Willst Du über die einzelnen Zeichen iterieren? Dann ist Dein Ansatz ungeeignet!

    var a = {
        array: ["eins", "zwei", "drei"],
        string: "eins zwei drei"
    };
    
    for (var eigenschaft in a) {
    
        for (var i=0; i < a[eigenschaft].length; i++) {
            console.log(a[eigenschaft][i]);
        }
    }
    
    /* Ausgabe der Browser-Console:
    eins debugger eval code:9:9
    zwei debugger eval code:9:9
    drei debugger eval code:9:9
    e debugger eval code:9:9
    i debugger eval code:9:9
    n debugger eval code:9:9
    s debugger eval code:9:9
     debugger eval code:9:9
    z debugger eval code:9:9
    w debugger eval code:9:9
    e debugger eval code:9:9
    i debugger eval code:9:9
     debugger eval code:9:9
    d debugger eval code:9:9
    r debugger eval code:9:9
    e debugger eval code:9:9
    i debugger eval code:9:9
    */
    

    Hier hast Du beide Herangehensweisen vorgeführt.

    Liebe Grüße,

    Felix Riesterer.

  3. Hallo heinetz,

    sehe ich es richtig, dass Du eine Funktion hast, die als Eingabe entweder einen Wert oder ein Array aus Werten bekommt, und Du einen einzelnen Wert wie ein Array mit einem Wert darin verarbeiten willst? Ich sage bewusst nicht String - denn wenn Du das voraussetzt müsstest Du das ja eigentlich auch prüfen...

    Nützlich wäre eigentlich eine Aufteilung in 2 Funktionen. Die eine kümmert sich um die Schnittstelle, die andere um die Aufgabe (das „do something“). Also grundsätzlich so:

    function doSomething(value) {
       if (Array.isArray(value)) {
          value.forEach(v => reallyDoSomething(v));
    // oder
          for (var i=0; i<value.length; i++)
             reallyDoSomething(value[i]);
       }
       else
          reallyDoSomething(value);
    }
    

    Das kann man sogar auf "forEach-fähige" Dinge verallgemeinern:

    function doSomething(value) {
       if (value && value.forEach) {
          value.forEach(v => reallyDoSomething(v));
       }
       else
          reallyDoSomething(value);
    }
    

    Die reallyDoSomething-Funktion erledigt dann die eigentliche Aufgabe.

    Das wird blöd, wenn die reallyDoSomething-Funktion eine Form von Kontext braucht, mit dem sie ihre Aufgabe erledigen soll. Wenn Du eine Minimumsuche baust, muss reallyDoSomething den bisher gefundenen minimalen Wert speichern. Wenn die Strings / der String irgendwo hin geschrieben werden sollen, braucht reallyDoSomething das Ziel des Schreibvorgangs.

    Das blödeste ist, dass Du hier eigentlich einen forEach-/single-value Adapter gebaut hast und sowas eigentlich ein schickes Tool ist. Warum also diesen Adapter nicht klar als solchen nutzen und die reallyDoSomething-Funktion einfach als Parameter hineinschieben? Dann bringt sie als Closure auch gleich ihren Aufrufkontext mit, was nützlich für den besagten Kontext sein kann.

    function callForValues(value, action) {
       if (value && value.forEach) {
          value.forEach((v,i) => action(v, i));
       }
       else
          action(value, 0);
    }
    

    Die action bekommt zwei Parameter: den Wert und den Index des Wertes. Verwendung:

      callForValues( [ "foo", "bar", "baz" ], logValues);
      callForValues( "hugo", logValues);
    
      function logValues(val, pos) {
         console.log("Wert " + pos + " ist " + (val == null ? "<null>" : val));
      }
    

    logValues gibt genau einen Wert zusammen mit seiner Position aus, und callForValues kümmert sich um den Unterschied "ein Wert" vs "forEach-fähige Sammlung von Werten".

    Natürlich bist Du aufgeschmissen, wenn dein "Wert" ein Array ist, d.h. du entweder ein Array oder ein Array aus Arrays als Input bekommst. Dann musst Du eine spezialisierte Prüfung programmieren. Das Trennen der Logik in "Einzelverarbeitung vs Mengenverabeitung" und "Verarbeite einen einzelnen Wert" ist aber auch da hilfreich.

    HTH
    Rolf

    --
    sumpsi - posui - clusi
  4. Ich hab's nun so gelöst:

    var my_array = [].concat(my_array);

    gruss, heinetz

    1. Tach!

      Ich hab's nun so gelöst:

      var my_array = [].concat(my_array);

      Du nutzt hier eine Nebenwirkung von concat() aus. Der Ausdruck macht was er soll, ist aber nicht sehr einleuchtend. Man muss dazu wissen, dass die die Funktion, die eigentlich Arrays miteinander verbinden soll, in diesem Falle zweigeteilt arbeitet. Arrays werden ausgepackt und deren Elemente an das erste Array angehängt, Nicht-Arrays werden einfach so angehängt.

      Ich bin in so einem Fall unentschlossen, wie ich das werte. Einerseits sollte man seine Werkzeuge kennen und im Zweifelsfall nachschlagen, wie sie genau funktionieren. Andererseits sind solche Nicht-Offensichtlichkeiten gern Quellen für Probleme.

      Das Problem lässt sich möglicherweie auch auf ganz andere Weise lösen. Angenommen, dein my_array ist eine Variable in einer Funktionssignatur, dann käme das Problem gar nicht erst auf, wenn du da nur Arrays erwarten würdest. Jeder, der da Einzelwerte übergeben möchte, muss stattdessen das Problem auf seiner Seite lösen. Aber das ist in dem Fall sogar noch mit insgesamt deutlich weniger Code zu haben.

      function my_function(my_array) {
          myArray.forEach(...);
      }
      

      Der Aufrufer übergibt nun Arrays einfach so, Nicht-Arrays hingegen werden mit einem simplen [] darum in Ein-Element-Arrays konvertiert.

      my_function(an_array);
      my_function([a_string]);
      

      dedlfix.

  5. Allerdings geht das doch sicher auch kürzer resp. eleganter, oder?

    Eine Variable, die zur Laufzeit Werte verschiedener Typen annehmen kann, ist ein Indiz dafür, dass die Variable für mindestens zwei verschiedene Zwecke benutzt wird. Ich würde das Problem bei der Wurzel packen und diese Fälle auseinander dividieren. Ein Typchecker kann dabei behilflich sein, indem er die problematischen Stellen moniert.

    Ich hab mal ein kleines Online-Beispiel gebastelt, um das zu demonstrieren.

    function something(foo) {
      return foo ? [] : '';
    }
    
    const myArray = something(true);
    for (var item in myArray) {
      console.log(item);
    }
    

    Im Online-Editor wird das Vorkommen von myArray in der for-Schleife bemängelt und mit einer Fehlermeldung versehen.

    PS: Den TypeScript-Typechecker kannst du auch für normales JavaSript nutzen. Im gezeigten Code wird ja beispielsweise auch kein exklusives TypeScript-Feature benutzt, sondern nur herkömmliches JavaScript.

    1. Tach!

      Allerdings geht das doch sicher auch kürzer resp. eleganter, oder?

      Eine Variable, die zur Laufzeit Werte verschiedener Typen annehmen kann, ist ein Indiz dafür, dass die Variable für mindestens zwei verschiedene Zwecke benutzt wird.

      Ja, geht aber manchmal nicht anders. Wenn null/undefined ebenfalls ein gültiger Wert sein darf, sind das schon zwei Typen. Aber auch dass man keine gleichnamigen Funktionen mit unterschiedlichen Signaturen haben kann, macht es manchmal nötig, dass die Parametervariable mehrere Typen hat.

      Ich würde das Problem bei der Wurzel packen und diese Fälle auseinander dividieren. Ein Typchecker kann dabei behilflich sein, indem er die problematischen Stellen moniert.

      Geht halt nicht immer. Man kann dem Typchecker auch behilflich sein, dass der Ruhe gibt.

      Ich hab mal ein kleines Online-Beispiel gebastelt, um das zu demonstrieren.

      function something(foo) {
        return foo ? [] : '';
      }
      
      const myArray = something(true);
      for (var item in myArray) {
        console.log(item);
      }
      

      Im Online-Editor wird das Vorkommen von myArray in der for-Schleife bemängelt und mit einer Fehlermeldung versehen.

      Wenn man die beabsichtige Lösung einbaut und alles, was kein Array ist, in ein solches konvertiert, ist er auch wieder friedlich, ganz ohne any oder string|string[] als Typangabe.

      const myArray = [].concat(something(true));
      

      Auch wenn man es etwas ausdrücklicher macht und keine Nebenwirkung von concat() ausnutzt:

      const value = something(true);
      const myArray = Array.isArray(value) ? value : [value];
      

      Im Original ist der Zwischenschritt value nicht nötig, weil der Wert bereits in einer Variable vorliegt.

      dedlfix.

      1. Allerdings geht das doch sicher auch kürzer resp. eleganter, oder?

        Eine Variable, die zur Laufzeit Werte verschiedener Typen annehmen kann, ist ein Indiz dafür, dass die Variable für mindestens zwei verschiedene Zwecke benutzt wird.

        Ja, geht aber manchmal nicht anders. Wenn null/undefined ebenfalls ein gültiger Wert sein darf, sind das schon zwei Typen.

        null und undefined sorgen ihrerseits für mehr Probleme als Lösungen, aber ja, manchmal muss man sich damit rumschlagen.

        Aber auch dass man keine gleichnamigen Funktionen mit unterschiedlichen Signaturen haben kann, macht es manchmal nötig, dass die Parametervariable mehrere Typen hat.

        Stimmt, das ist eine Schwäche von TypeScript, die die Sprache wahrscheinlich auch nicht überwinden wird, weil eines der Design-Ziele – JavaScript-Kompatibilität – damit in Konflikt steht. Die Alternative wäre, die Funktionen unterschiedlich zu bennnen. Wenn das auch keine Möglichkeit ist, dann hilft nur ein Laufzeit-Typecheck.

        Ich würde das Problem bei der Wurzel packen und diese Fälle auseinander dividieren. Ein Typchecker kann dabei behilflich sein, indem er die problematischen Stellen moniert.

        Geht halt nicht immer.

        Richtig.

        Man kann dem Typchecker auch behilflich sein, dass der Ruhe gibt.

        Womit ja auch wieder ein potenzieller Laufzeitfehler behoben wurde.

        Wenn man die beabsichtige Lösung einbaut und alles, was kein Array ist, in ein solches konvertiert, ist er auch wieder friedlich, ganz ohne any oder string|string[] als Typangabe.

        Mein Beispiel macht auch keinen Gebrauch von ausdrücklichen Typangaben.

        Auch wenn man es etwas ausdrücklicher macht und keine Nebenwirkung von concat() ausnutzt:

        const value = something(true);
        const myArray = Array.isArray(value) ? value : [value];
        

        Finde ich so auch deutlich besser lesbar.

    2. @@1unitedpower

      Eine Variable, die zur Laufzeit Werte verschiedener Typen annehmen kann, ist ein Indiz dafür, dass die Variable für mindestens zwei verschiedene Zwecke benutzt wird.

      Indizien können auch trügerisch sein.

      Beim Einlesen von JSON-Daten können Strings oder Arrays rauskommen:

      [
      	{
      		"name": "John Doe",
      		"telephone": "555 1234"
      	},
      	{
      		"name": "Jane Roe",
      		"telephone": ["555 1234", "555 9876"]
      	}
      ]
      

      LLAP 🖖

      --
      „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
      1. Beim Einlesen von JSON-Daten können Strings oder Arrays rauskommen:

        JSON definiert ja auch keinen speziellen Enctype bzw. Content-Type!

      2. Beim Einlesen von JSON-Daten können Strings oder Arrays rauskommen:

        [
        	{
        		"name": "John Doe",
        		"telephone": "555 1234"
        	},
        	{
        		"name": "Jane Roe",
        		"telephone": ["555 1234", "555 9876"]
        	}
        ]
        

        Das lässt sich einfach korrigieren:

        [
        	{
        		"name": "John Doe",
        		"telephone": ["555 1234"]
        	},
        	{
        		"name": "Jane Roe",
        		"telephone": ["555 1234", "555 9876"]
        	}
        ]
        
        1. @@1unitedpower

          Beim Einlesen von JSON-Daten können Strings oder Arrays rauskommen:

          [
          	{
          		"name": "John Doe",
          		"telephone": "555 1234"
          	},
          	{
          		"name": "Jane Roe",
          		"telephone": ["555 1234", "555 9876"]
          	}
          ]
          

          Das lässt sich einfach korrigieren:

          [
          	{
          		"name": "John Doe",
          		"telephone": ["555 1234"]
          	},
          	{
          		"name": "Jane Roe",
          		"telephone": ["555 1234", "555 9876"]
          	}
          ]
          

          Nein, das widerspricht Postels Gesetz (Robustheitsgrundsatz).

          {"telephone": "555 1234"} ist korrektes JSON. Es gibt keinen Grund, bei einer Telefonnummer eine Liste von Telefonnummern {"telephone": ["555 1234"]} zu notieren.

          Die Korrektur hat hier nicht in den Daten zu erfolgen, sondern im auswertenden Programm: “be liberal in what you accept.”

          LLAP 🖖

          --
          „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
          1. Tach!

            Beim Einlesen von JSON-Daten können Strings oder Arrays rauskommen:

            [
            	{
            		"name": "John Doe",
            		"telephone": "555 1234"
            	},
            	{
            		"name": "Jane Roe",
            		"telephone": ["555 1234", "555 9876"]
            	}
            ]
            

            Das lässt sich einfach korrigieren:

            [
            	{
            		"name": "John Doe",
            		"telephone": ["555 1234"]
            	},
            	{
            		"name": "Jane Roe",
            		"telephone": ["555 1234", "555 9876"]
            	}
            ]
            

            Nein, das widerspricht Postels Gesetz (Robustheitsgrundsatz).

            {"telephone": "555 1234"} ist korrektes JSON. Es gibt keinen Grund, bei einer Telefonnummer eine Liste von Telefonnummern {"telephone": ["555 1234"]} zu notieren.

            Ein einzelner String mit Trennzeichen darin ist auch korrektes JSON. Und trotzdem wird niemand auf die Idee kommen, das ebenfalls zuzulassen, wenn es dazu keinen besonderen Grund gibt.

            Ebenso könntest du auch auf die Idee kommen, wenn nur ein Datensatz in der Menge ist, dass man da auch das äußere Array weglassen könnte. Sowas macht die Angelegenheit nur unnötig komplex, sowohl beim Auswerten als auch beim Formulieren der Schnittstellenbeschreibung.

            Die Korrektur hat hier nicht in den Daten zu erfolgen, sondern im auswertenden Programm: “be liberal in what you accept.”

            Der Herr Postel ist kein unumgängliches Gesetz formuliert, zu dem es keine Alternativen gibt. Der Abschnitt fängt an mit "TCP implementations should follow ...". Should, nicht must.

            Auch hat so ein Grundsatz seine technischen Grenzen, weil irgendwann die Mehrdeutigkeit zu groß geworden ist. Systeme, die stillschweigend Korrekturen vornehmen, statt auf Probleme aufmerksam zu machen, sind auch nicht immer der Weisheit letzter Schluss.

            Und wir sind hier nicht zwangsläufig in einem Umfeld, wo man sehr viele Implementationen aktueller und älterer Bauart zu berücksichtigen hat. Das ist erstmal ein konkret definiertes Datenformat. Wenn der Verwender das nicht korrekt implementiert, hat er keinen Anspruch darauf, dass sich andere Systeme ihn dann intentionsgemäß verstehen.

            dedlfix.

            1. @@dedlfix

              Ein einzelner String mit Trennzeichen darin ist auch korrektes JSON. Und trotzdem wird niemand auf die Idee kommen, das ebenfalls zuzulassen, wenn es dazu keinen besonderen Grund gibt.

              Dass es hier um key/value-Paare geht, sollte klargeworden sein.

              Systeme, die stillschweigend Korrekturen vornehmen, statt auf Probleme aufmerksam zu machen, sind auch nicht immer der Weisheit letzter Schluss.

              {"telephone": "555 1234"} ebenso zu akzeptieren wie {"telephone": ["555 1234"]} sehe ich nicht als Problem an, auf das aufmerksam gemacht werden und das korrigiert werden müsste.

              Man kann verschienede Wege gehen:

              1. Die Daten bestimmen das Format. Man notiert die Daten so, wie sie nun einmal sind: eine Telefonnummer halt als einen String und nicht als Liste mit einem Eintrag (kann man auch, muss man aber nicht) – und baut die Software so, dass sie mit den Daten umgehen kann

              2. Die Software bestimmt das Datenformat. Die Software wird so gebaut, dass sie ein ganz bestimmtes Datenformat erwartet und bei Abweichungen davon mit Fehlermeldungen (im besten Fall aussagekräftige) aussteigt.

              Variante 1 ist robust. Variante 2 fliegt dir bei nächster Gelegenheit um die Ohren.

              Die robuste Variante bei mir letztens so aus: Ausgabe der Telefonnummer(n) in einer Tabellenzelle:

              if (subEvent.location && subEvent.location.telephone)
              {
              	tCellElement.classList.add('telephone');
              	tCellElement.textContent = (typeof subEvent.location.telephone === 'object') ? subEvent.location.telephone.join(', ') : subEvent.location.telephone;
              }
              

              LLAP 🖖

              --
              „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
              1. Tach!

                1. Die Daten bestimmen das Format. Man notiert die Daten so, wie sie nun einmal sind: eine Telefonnummer halt als einen String und nicht als Liste mit einem Eintrag (kann man auch, muss man aber nicht) – und baut die Software so, dass sie mit den Daten umgehen kann

                Und der nächste kommt und notiert sie als Nummer, weil wissenschon.

                1. Die Software bestimmt das Datenformat. Die Software wird so gebaut, dass sie ein ganz bestimmtes Datenformat erwartet und bei Abweichungen davon mit Fehlermeldungen (im besten Fall aussagekräftige) aussteigt.

                Variante 1 ist robust. Variante 2 fliegt dir bei nächster Gelegenheit um die Ohren.

                Variante 1 ist aufwendig, weil mehr Fälle berücksichtigt werden müssen. Variante 2 meldet sich gleich beim Programmieren. Dann korrigiert man seinen Fehler und anschließend läuft sie problemlos. Ich sehe nicht, dass es Vorteile auf beiden Seiten bringt, wenn man gemischt mit skalaren Werten und Arrays arbeitet, wenn sowohl ein als auch mehrere Werte vorhanden sein konnen. Arbeite gleich mit einem Array, dann herrscht Klarheit und die Verarbeitung muss nicht unterscheiden.

                dedlfix.

                1. @@dedlfix

                  Variante 1 ist aufwendig, weil mehr Fälle berücksichtigt werden müssen.

                  Jedes Programm ist aufwendig – außer diesem:

                  
                  

                  Die Frage ist: wieviel Aufwand? Eine Typprüfung – kaum der Rede wert. Macht sich der Aufwand bezahlt? Darauf kannste wetten.

                  Variante 2 meldet sich gleich beim Programmieren.

                  Eben nicht …

                  Dann korrigiert man seinen Fehler und anschließend läuft sie problemlos.

                  … die realen Daten kommen, wenn die Programmierung abgeschlossen ist. Und sie kommen von woanders, von jemand anderem, der sich völlig zurecht denkt: wozu sollte man eine Telefonnummer als Liste von Telefonnummern notieren?

                  Und wenn eine Person gar keine Telefonnummer hat bzw. keine bekannt ist, dann fehlt das Datum telephone eben ganz; da muss kein Datenmüll wie telephone: "" oder telephone: [] drinstehen. Die Software sollte so robust sein, mit nicht vorhandenen Daten umgehen zu können.

                  In meinem Beispiel: if (subEvent.location && subEvent.location.telephone). Ist das zu aufwendig?

                  Gerade JavaScript sollte robust programmiert werden, damit ein Browser nicht bei einem Fehler aussteigt und gar das Rendern der Webseite abbricht.

                  Ich sehe nicht, dass es Vorteile auf beiden Seiten bringt

                  Scheuklappen ab‽

                  LLAP 🖖

                  --
                  „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
                  1. Tach!

                    Variante 2 meldet sich gleich beim Programmieren.

                    Eben nicht …

                    Dann korrigiert man seinen Fehler und anschließend läuft sie problemlos.

                    … die realen Daten kommen, wenn die Programmierung abgeschlossen ist. Und sie kommen von woanders, von jemand anderem, der sich völlig zurecht denkt: wozu sollte man eine Telefonnummer als Liste von Telefonnummern notieren?

                    Wozu ein Label, ich hab doch ein Placeholder in meinem Input. Sowas ist eben zu kurz gedacht. Die realen Daten kommen nicht aus heiterem Himmel. Jemand muss die Anwendung, die diese Daten übergibt, programmieren. Und dabei fällt das Problem sofort auf, wenn man sich nicht an das festgelegte Datenformat hält. Dass zuerst der Client da wäre und dazu jemand einen Server schreibt und obendrein das Austauschformat nicht definiert ist, wäre eine ziemlich seltsame Konstellation.

                    Und wenn eine Person gar keine Telefonnummer hat bzw. keine bekannt ist, dann fehlt das Datum telephone eben ganz; da muss kein Datenmüll wie telephone: "" oder telephone: [] drinstehen. Die Software sollte so robust sein, mit nicht vorhandenen Daten umgehen zu können.

                    Und wenn mein Anwender denkt, dass zu den Telefonnummern noch Bemerkungen oder andere Metadaten angebracht wären, dann muss auch noch Objekt als Format zuverlässig erkannt werden, obwohl das auch nicht vereinbart ist? Wenn jedenfalls etwas optional ist, dann gibt es dafür eine Vereinbarung, dass es weggelassen werden kann.

                    In meinem Beispiel: if (subEvent.location && subEvent.location.telephone). Ist das zu aufwendig?

                    Es ist insgesamt auf beiden Seiten aufwendig die Fälle zu berücksichtigen. Der Sender muss ja auch eine Mechanik programmiert haben, der diese mit einem Default-Wert belegten Felder in seiner Datenstruktur rauskürzt. Warum sollte man sowas programmieren, wenn das Format an der Stelle nicht optional ist?

                    Gerade JavaScript sollte robust programmiert werden, damit ein Browser nicht bei einem Fehler aussteigt und gar das Rendern der Webseite abbricht.

                    Ja, wenn es um Kompatibilität zwischen Javascript und Browsergegebenheiten geht. Aber hier geht es um den Austausch von Daten nach einem vereinbartem Format.

                    Ich sehe nicht, dass es Vorteile auf beiden Seiten bringt

                    Scheuklappen ab‽

                    Keine überzeugenden Argumente deinerseits.

                    dedlfix.

                    1. @@dedlfix

                      Und wenn mein Anwender denkt, dass zu den Telefonnummern noch Bemerkungen oder andere Metadaten angebracht wären, dann muss auch noch Objekt als Format zuverlässig erkannt werden, obwohl das auch nicht vereinbart ist?

                      Nein. Sie müssen nicht erkannt werden, sondern können ignoriert werden, wenn man sie nicht verarbeiten will. Beispiel:

                      	{
                      		"name": "John Doe",
                      		"telephone": "555 1234",
                      		"fax": "555 9876"
                      	}
                      

                      Wen interessiert schon noch Johns Faxnummer?

                      Der Sender muss ja auch eine Mechanik programmiert haben, der diese mit einem Default-Wert belegten Felder in seiner Datenstruktur rauskürzt. Warum sollte man sowas programmieren, wenn das Format an der Stelle nicht optional ist?

                      Nein. Der Sender könnte ein RDFa-Parser sein, der Informationen aus einer Webseite ausliest und in JSON packt. Warum sollte der key/empty value-Paare für nicht vorhandene Informationen anlegen, zumal er gar nicht wissen kann, dass irgendwelche Software die erwartet?

                      Ja, wenn es um Kompatibilität zwischen Javascript und Browsergegebenheiten geht. Aber hier geht es um den Austausch von Daten nach einem vereinbartem Format.

                      Hier geht es darum, wie flexibel das Format vereinbart wird.

                      LLAP 🖖

                      --
                      „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
                      1. Hallo Gunnar Bittersmann,

                        Hier geht es darum, wie flexibel das Format vereinbart wird.

                        Das Array ist sehr flexibel.

                        Bis demnächst
                        Matthias

                        --
                        Pantoffeltierchen haben keine Hobbys.
                        ¯\_(ツ)_/¯
                      2. Tach!

                        Nein. Der Sender könnte ein RDFa-Parser sein, der Informationen aus einer Webseite ausliest und in JSON packt. Warum sollte der key/empty value-Paare für nicht vorhandene Informationen anlegen, zumal er gar nicht wissen kann, dass irgendwelche Software die erwartet?

                        Wir reden anscheinend die ganze Zeit aneinander vorbei, weil wir jeweils verschiedene Anwendungsfälle vor Augen haben. Dein Datenformat ist von vorn herein flexibel ausgelegt, weil dessen Quelle dazu flexibel definiert ist. Das heißt nicht, dass man so eine Situation verallgemeinern muss, und dass das nun das Maß aller Dinge sei und überall so angewendet werden muss. Deine Vorgehensweise mag vorteilhaft für deinen Fall sein, für andere ist es das nicht. Alles weitere muss man für den jeweiligen Fall betrachten.

                        dedlfix.

                        1. @@dedlfix

                          Wir reden anscheinend die ganze Zeit aneinander vorbei, weil wir jeweils verschiedene Anwendungsfälle vor Augen haben. Dein Datenformat ist von vorn herein flexibel ausgelegt, weil dessen Quelle dazu flexibel definiert ist. Das heißt nicht, dass man so eine Situation verallgemeinern muss, und dass das nun das Maß aller Dinge sei und überall so angewendet werden muss.

                          Ich hatte anfangs im Thread ein Beispiel dafür gegeben, dass „eine Variable, die zur Laufzeit Werte verschiedener Typen annehmen kann“ nicht zwangläufig „für mindestens zwei verschiedene Zwecke benutzt wird.“

                          Ich war es nicht, der hier den Anwedungsfall eines stringenten Datenformats verallgemeinert hat.

                          LLAP 🖖

                          --
                          „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
            2. Ich bin da voll bei Dir. JSON dient zum Datentransport. Also sollte die Schnittstelle und damit die Datenstruktur möglichst genau definiert sein. Und ein Programm, welches sich nicht daran hält, ist einfach mal fehlerhaft.

              Ebenso könntest du auch auf die Idee kommen, wenn nur ein Datensatz in der Menge ist, dass man da auch das äußere Array weglassen könnte. Sowas macht die Angelegenheit nur unnötig komplex, sowohl beim Auswerten als auch beim Formulieren der Schnittstellenbeschreibung.

              "Formulieren der Schnittstellenbeschreibung" - Das ist ein Ansatz. Schon in dieser Formulierung sollte man wohl etwas wie eine Versionsnummer aufnehmen, die bei der Anforderung und in der Antwort hinterlegt wird. Mit einer solchen Idee kann man dann auch zukünftige Anforderungen bedienen ohne dass alle Clients und der Server gleichzeitig ein Update oder Upgrade erhalten. Freilich kann man das auch über die URL regeln aber wenn wir weiter denken als bis zum Browser, womöglich sogar an eine lokale Speicherung der Daten beim Empfänger, dann wäre es wohl in manchen Fällen nützlich, die Version der Schnittstellendefinition, mit der die Daten geliefert wurden, zur Hand zu haben.

              Vorliegend käme also in Betracht bei einer Schnittstellen-Version "0815" hinsichtlich der Eigenschaft "telephone" einen String, bei "0816" einen Array zu erwarten.

          2. meun,

            {"telephone": "555 1234"} ist korrektes JSON. Es gibt keinen Grund, bei einer Telefonnummer eine Liste von Telefonnummern {"telephone": ["555 1234"]} zu notieren.

            Was aber auch korrekt ist. Denn: JSON definiert keinen speziellen Enctype.

            Die Korrektur hat hier nicht in den Daten zu erfolgen, sondern im auswertenden Programm: “be liberal in what you accept.”

            Die Korrektur ist eine Frage der Vereinbarung. So darf es beim Enctype application/x-www-form-urlencoded auch mehrere Werte zu einem Parameter geben -- Was man als Liste auffassen kann. Oder man erzeugt damit eine eigene Datenstruktur wie PHP das tut sofern der Parametername bestimmten Anforderungen genügt.

            GG