NAME

Quiq::Json - Erzeuge JSON-Code in Perl

BASE CLASS

Quiq::Hash

SYNOPSIS

Klasse laden und Objekt instantiieren

  use Quiq::Json;
  
  my $j = Quiq::Json->new;

JSON-Objekt via object()

  $json = $j->object(
      pi => 3.14159,
      str => 'Hello world!',
      bool => \'true',
      obj => $j->object(
          id => 4711,
          name => 'Wall',
          numbers => [1..5],
      ),
      min => undef,
  );

erzeugt

  {
      pi: 3.14159,
      str: 'Hello world!',
      bool: true,
      obj: {
          id: 4711,
          name: 'Wall',
          numbers: [1,2,3,4,5],
      },
      min: undefined,
  }

Bei der Methode $j->object()

  • bleibt die Reihenfolge der Schlüssel/Wert-Paare erhalten

  • jedes Schlüssel/Wert-Paar beginnt auf einer eigenen Zeile und wird eingerückt

JSON-Datenstruktur via encode()

  $json = $j->encode({
      pi => 3.14159,
      str => 'Hello world!',
      bool => \'true',
      obj => {
          id => 4711,
          name => 'Wall',
          numbers => [1..5],
      },
      min => undef,
  });

erzeugt

  {bool:true,min:undefined,obj:{id:4711,name:'Wall',numbers:[1,2,3,4,5]},pi:3.14159,str:'Hello world!'}

Bei der Methode $j->encode()

  • werden die Schlüssel/Wert-Paare von JSON-Objekten alphanumerisch sortiert (bei {...} ist die Reihenfolge sonst undefiniert)

  • gibt es keine Einrückung oder Leerraum nach dem :

DESCRIPTION

Die Klasse ermöglicht die präzise Erzeugung von JavaScript-Datenstrukturen aus Perl heraus. Der Fokus liegt nicht auf der Übermittlung von Daten, sondern auf der Einsetzung der Strukturen in JavaScript-Quelltexte. Insofern gehen die Möglichketen der Klasse über JSON hinaus. Die JavaScript-Klasse Chart.js arbeitet z.B. mit einer komplexen Datenstruktur. Diese Struktur aus Perl heraus dynamisch erzeugen zu können, war der Anlass für die Entwicklung dieser Klasse. Das Perl-Modul JSON ist für diese Zwecke nicht geeignet, denn z.B. kann eine JavaScript-Datenstruktur Referenzen auf (inline definierte) JavaScript-Funktionen enthalten. Dies ist mit dieser Klasse möglich. Weitere Vorteile dieser Klasse:

  • die Reihenfolge von Objektattributen bleibt erhalten

  • Werte können literal eingesetzt werden (z.B. Funktionsdefinionen, spezielle Werte wie true, false, null usw.)

  • lesbarerer Code

EXAMPLE

Ein realer Fall. Die Erzeugung einer Konfiguration für Chart.js. Wir nutzen hier die Aliase o() und c() für die Methoden object() und code().

  my @dataSets;
  my $title = 'Windspeed';
  my $unit = 'm/s';
  my $tMin = undef;
  my $tMax = undef;
  my $yMin = 0;
  my $yMax = undef;
  
  $json = $j->o(
      type => 'line',
      data => $j->o(
          datasets => \@dataSets,
      ),
      options => $j->o(
          maintainAspectRatio => \'false',
          title => $j->o(
              display => \'true',
              text => $title,
              fontSize => 16,
              fontStyle => 'normal',
          ),
          tooltips => $j->o(
              intersect => \'false',
              displayColors => \'false',
              backgroundColor => 'rgb(0,0,0,0.6)',
              titleMarginBottom => 2,
              callbacks => $j->o(
                  label => $j->c(qq~
                      function(tooltipItem,data) {
                          var i = tooltipItem.datasetIndex;
                          var label = data.datasets[i].label || '';
                          if (label)
                              label += ': ';
                          label += tooltipItem.value + ' $unit';
                          return label;
                      }
                  ~),
              ),
          ),
          legend => $j->o(
              display => \'false',
          ),
          scales => $j->o(
              xAxes => [$j->o(
                  type => 'time',
                  ticks => $j->o(
                      minRotation => 30,
                      maxRotation => 60,
                  ),
                  time => $j->o(
                      min => $tMin,
                      max => $tMax,
                      minUnit => 'second',
                      displayFormats => $j->o(
                          second => 'YYYY-MM-DD HH:mm:ss',
                          minute => 'YYYY-MM-DD HH:mm',
                          hour => 'YYYY-MM-DD HH',
                          day => 'YYYY-MM-DD',
                          week => 'YYYY-MM-DD',
                          month => 'YYYY-MM',
                          quarter => 'YYYY [Q]Q',
                          year => 'YYYY',
                      ),
                      tooltipFormat => 'YYYY-MM-DD HH:mm:ss',
                  ),
              )],
              yAxes => [$j->o(
                  ticks => $j->o(
                      min => $yMin,
                      max => $yMax,
                  ),
                  scaleLabel => $j->o(
                      display => \'true',
                      labelString => $unit,
                  ),
              )],
          ),
      ),
  );

erzeugt

  {
      type: 'line',
      data: {
          datasets: [],
      },
      options: {
          maintainAspectRatio: false,
          title: {
              display: true,
              text: 'Windspeed',
              fontSize: 16,
              fontStyle: 'normal',
          },
          tooltips: {
              intersect: false,
              displayColors: false,
              backgroundColor: 'rgb(0,0,0,0.6)',
              titleMarginBottom: 2,
              callbacks: {
                  label: function(tooltipItem,data) {
                      var i = tooltipItem.datasetIndex;
                      var label = data.datasets[i].label || '';
                      if (label)
                          label += ': ';
                      label += tooltipItem.value + ' m/s';
                      return label;
                  },
              },
          },
          legend: {
              display: false,
          },
          scales: {
              xAxes: [{
                  type: 'time',
                  ticks: {
                      minRotation: 30,
                      maxRotation: 60,
                  },
                  time: {
                      min: undefined,
                      max: undefined,
                      minUnit: 'second',
                      displayFormats: {
                          second: 'YYYY-MM-DD HH:mm:ss',
                          minute: 'YYYY-MM-DD HH:mm',
                          hour: 'YYYY-MM-DD HH',
                          day: 'YYYY-MM-DD',
                          week: 'YYYY-MM-DD',
                          month: 'YYYY-MM',
                          quarter: 'YYYY [Q]Q',
                          year: 'YYYY',
                      },
                      tooltipFormat: 'YYYY-MM-DD HH:mm:ss',
                  },
              }],
              yAxes: [{
                  ticks: {
                      min: 0,
                      max: undefined,
                  },
                  scaleLabel: {
                      display: true,
                      labelString: 'm/s',
                  },
              }],
          },
      },
  }

METHODS

Instantiierung

new() - Konstruktor

Synopsis

  $j = $class->new(@keyVal);

Attributes

indent => $n (Default: 4)

Tiefe der Einrückung.

Returns

Objekt

Description

Instantiiere ein Objekt der Klasse und liefere eine Referenz auf dieses Objekt zurück.

Objektmethoden

code() - Erzeuge Sourcecode für JSON-Datenstruktur

Synopsis

  $code = $j->code($text);    # Scalar-Kontext
  ($codeS) = $j->code($text); # List-Kontext

Alias

c()

Arguments

$text

Sourcecode, typischerweise mehrzeiliger JavaScript-Code.

Returns

Sourecode (String). Im List-Kontext eine Referenz auf den Code.

Description

Erzeuge Sourcecode, der in eine JSON-Datenstruktur eingebettet werden kann, und liefere diesen zurück. Der Code

  • erhält die richtige Einrückung

  • wird "as is" eingebettet, also nicht gequotet

Example

Weise Funktionsreferenz an Objekt-Attribut zu

  $unit = 'm/s';
  $json = $j->object(
      label => $j->code(qq~
          function(tooltipItem,data) {
              var i = tooltipItem.datasetIndex;
              var label = data.datasets[i].label || '';
              if (label)
                  label += ': ';
              label += tooltipItem.value + ' $unit';
              return label;
          }
      ~),
  ),

liefert

  {
      label: function(tooltipItem,data) {
          var i = tooltipItem.datasetIndex;
          var label = data.datasets[i].label || '';
          if (label)
              label += ': ';
          label += tooltipItem.value + ' m/s';
          return label;
      },
  }

encode() - Wandele Perl- in JavaScript-Datenstruktur

Synopsis

  $json = $j->encode($scalar);

Arguments

$scalar

Skalarer Wert: undef, \0, \1, Number, String, String-Referenz, Array-Referenz, Hash-Referenz.

Returns

JSON-Code (String)

Description

Wandele $scalar nach JSON und liefere den resultierenden Code zurück. Die Übersetzung erfolgt (rekursiv) nach folgenden Regeln:

undef

Wird abgebildet auf: undefined. In einem Objekt wird das betreffende Attribut weggelassen.

\1 oder \'true'

Wird abgebildet auf: true

\0 oder \'false'

Wird abgebildet auf: false

NUMBER

Wird unverändert übernommen: NUMBER

STRING

Wird abgebildet auf: 'STRING'

STRING_REF

Wird abgebildet auf: STRING (literale Einsetzung von STRING)

Dies ist z.B. nützlich, wenn ein Teil der Datenstruktur abweichend formatiert werden soll.

ARRAY_REF

Wird abgebildet auf: [ELEMENT1,ELEMENT2,...]

HASH_REF

Wird abgebildet auf: {KEY1:VALUE1,KEY2:VALUE2,...}. Im Falle des Werts undef, wird das betreffende Schlüssel/Wert-Paar weggelassen.

object() - Erzeuge Code für JSON-Objekt

Synopsis

  $json = $j->object(@opt,@keyVal);    # Scalar-Kontext
  ($jsonS) = $j->object(@opt,@keyVal); # List-Kontext

Alias

o()

Arguments

@keyVal

Liste der Schlüssel/Wert-Paare

Options

-indent => $bool (Default: 1)

Rücke die Elemente des Hash ein.

Returns

JSON-Code (String). Im List-Kontext eine Referenz auf den Code.

Description

Erzeuge den Code für ein JSON-Objekt mit den Attribut/Wert-Paaren @keyVal und liefere diesen zurück.

Hilfsmethoden

key() - Schlüssel eines JSON-Objekts

Synopsis

  $str = $j->key($key);

Arguments

$key

Schlüssel.

Returns

String

Description

Erzeuge den Code für den Schlüssel $key eines JSON-Objekts und liefere diesen zurück. Enthält der Schlüssel nur Zeichen, die in einem JavaScript-Bezeichner vorkommen dürfen, wird er unverändert geliefert, ansonsten wird er in einfache Anführungsstriche eingefasst.

Example

Schlüssel aus dem Zeichenvorrat eines JavaScript-Bezeichners:

  $str = $j->Quiq::Json('borderWidth');
  ==>
  "borderWidth"

Schlüssel mit Zeichen, die nicht in einem JavaScript-Bezeichner vorkommen:

  $str = $j->Quiq::Json('border-width');
  ==>
  "'border-width'"

VERSION

1.187

AUTHOR

Frank Seitz, http://fseitz.de/

COPYRIGHT

Copyright (C) 2020 Frank Seitz

LICENSE

This code is free software; you can redistribute it and/or modify it under the same terms as Perl itself.