JsonMod - Lokale Datei auslesen

Begonnen von Stargazer, 05 Januar 2023, 21:30:49

Vorheriges Thema - Nächstes Thema

Stargazer

Hallo zusammen,

ich grabe diesen Thread noch einmal aus, da ich aktuell noch einmal euren Rat/Tipp brauche.

Ich würde gerne eine json-Datei parsen. Ebenfalls wieder über die 99_myUtils. Diesesmal jedoch scheint mir JSON - Datei nicht so komplex zu sein,
wie der Vorgänger.

Hier einmal der Inhalt der JSON-Datei:

{'ret_code': 0, 'ret_msg': 'OK', 'result': [{'user_id': 51101317, 'symbol': 'BTCUSDT', 'side': 'None', 'size': 0, 'position_value': 0, 'entry_price': 0, 'liq_price': 0, 'bust_price': 0, 'leverage': 1, 'auto_add_margin': 0, 'is_isolated': True, 'position_margin': 0, 'occ_closing_fee': 0, 'realised_pnl': -0.1473463, 'cum_realised_pnl': -0.2546504, 'free_qty': 0, 'tp_sl_mode': 'Full', 'unrealised_pnl': 0, 'deleverage_indicator': 0, 'risk_id': 1, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0, 'position_idx': 0, 'mode': 'MergedSingle'}], 'ext_code': '', 'ext_info': '', 'time_now': '1674316840.217231', 'rate_limit_status': 119, 'rate_limit': 120, 'rate_limit_reset_ms': 1674316840212}

Dazu hatte ich folgenden Eintrag zum testen in die Utils geschrieben:

use Data::Dumper;
sub test {
  my ($err,@input) = FileRead({FileName=>'/home/pi/BTCOrderInfoByBit.txt', ForceType=>'file'});
  return $err if $err;
  my $json = join ("",@input);
  ##$json =~ s/^getPositions.*{/{/;
  $json =~ s/'$//;
  return Dumper json2nameValue($json);
}


Und die Antwort seitens FHEM:

$VAR1 = {
          'json2nameValueInput' => '{\'ret_code\': 0, \'ret_msg\': \'OK\', \'result\': [{\'user_id\': 51101317, \'symbol\': \'BTCUSDT\', \'side\': \'None\', \'size\': 0, \'position_value\': 0, \'entry_price\': 0, \'liq_price\': 0, \'bust_price\': 0, \'leverage\': 1, \'auto_add_margin\': 0, \'is_isolated\': True, \'position_margin\': 0, \'occ_closing_fee\': 0, \'realised_pnl\': -0.1473463, \'cum_realised_pnl\': -0.2546504, \'free_qty\': 0, \'tp_sl_mode\': \'Full\', \'unrealised_pnl\': 0, \'deleverage_indicator\': 0, \'risk_id\': 1, \'stop_loss\': 0, \'take_profit\': 0, \'trailing_stop\': 0, \'position_idx\': 0, \'mode\': \'MergedSingle\'}], \'ext_code\': \'\', \'ext_info\': \'\', \'time_now\': \'1674316840.217231\', \'rate_limit_status\': 119, \'rate_limit\': 120, \'rate_limit_reset_ms\': 1674316840212}',
          'json2nameValueErrorText' => 'error parsing (#1) \'\'ret_code\': 0, \'ret_msg\': \'OK\', \'result\': [{\'user_id\': 51101317, \'symbol\': \'BTCUSDT\', \'side\': \'None\', \'size\': 0, \'position_value\': 0, \'entry_price\': 0, \'liq_price\': 0, \'bust_price\': 0, \'leverage\': 1, \'auto_add_margin\': 0, \'is_isolated\': True, \'position_margin\': 0, \'occ_closing_fee\': 0, \'realised_pnl\': -0.1473463, \'cum_realised_pnl\': -0.2546504, \'free_qty\': 0, \'tp_sl_mode\': \'Full\', \'unrealised_pnl\': 0, \'deleverage_indicator\': 0, \'risk_id\': 1, \'stop_loss\': 0, \'take_profit\': 0, \'trailing_stop\': 0, \'position_idx\': 0, \'mode\': \'MergedSingle\'}], \'ext_code\': \'\', \'ext_info\': \'\', \'time_now\': \'1674316840.217231\', \'rate_limit_status\': 119, \'rate_limit\': 120, \'rate_limit_reset_ms\': 1674316840212\''
        };


Ich denke, es ist wieder nur so eine kleine Sache... :o

Viele Grüße und besten Dank für einen kleinen Tipp

André

betateilchen

Wie man den von Dir zitierten Fehlermeldungen entnehmen kann, lieferst Du wieder keinen für json2nameValue() gültigen Input.

Problem 1: einfache Anführungszeichen anstatt doppelte
Problem 2: der logische Wert True steht nicht in Anführungszeichen.

Insbesondere zu 2 sei angemerkt, dass das zwar syntaktisch für JSON so korrekt ist, aber die Funktion json2nameValue() damit nicht zurecht kommt.

Beide Probleme lassen sich durch geeignete regex lösen, dann käme am Ende sowas raus:


$VAR1 = {
          'ext_info' => '',
          'result_1_size' => '0',
          'result_1_position_margin' => '0',
          'result_1_position_value' => '0',
          'result_1_take_profit' => '0',
          'result_1_bust_price' => '0',
          'result_1_mode' => 'MergedSingle',
          'result_1_is_isolated' => 'True',
          'result_1_user_id' => '51101317',
          'result_1_position_idx' => '0',
          'result_1_leverage' => '1',
          'rate_limit' => '120',
          'result_1_occ_closing_fee' => '0',
          'result_1_tp_sl_mode' => 'Full',
          'rate_limit_reset_ms' => '1674316840212',
          'ret_code' => '0',
          'time_now' => '1674316840.217231',
          'result_1_unrealised_pnl' => '0',
          'result_1_trailing_stop' => '0',
          'result_1_realised_pnl' => '-0.1473463',
          'result_1_side' => 'None',
          'result_1_auto_add_margin' => '0',
          'ext_code' => '',
          'result_1_stop_loss' => '0',
          'result_1_liq_price' => '0',
          'rate_limit_status' => '119',
          'result_1_symbol' => 'BTCUSDT',
          'result_1_free_qty' => '0',
          'result_1_entry_price' => '0',
          'ret_msg' => 'OK',
          'result_1_risk_id' => '1',
          'result_1_deleverage_indicator' => '0',
          'result_1_cum_realised_pnl' => '-0.2546504'
        };
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Stargazer

Hallo betateilchen,

vielen Dank für deine Antwort. So wie du mir das geschrieben hast, würde ich aus der Zeile:

my $json = join ("",@input);   ->   my $json = join ('',@input); machen.

Wäre das zu Punkt 1 schonmal der richtige Weg ?

Bei Punkt zwei muss ich mich echt rein Knien. Habe da schon Ansätze mit der Ausgabe auf https://www.regextester.com/ gemacht.
Habe bis jetzt jedoch immer so eingermaßen mit den HTTPMOD - Regex arbeiten können, also immer normales HTTP Format.
Aber JSON scheint irgendwie anders zu sein.. ::)

VG

betateilchen

regex ist überall gleich - das hat überhaupt nichts mit perl, FHEM oder irgendeinem FHEM Modul zu tun.

Und nein, mit Deinen Änderungen an join() bist Du komplett auf dem Holzweg.
Die Anführungszeichen sind schon in den Quelldaten (Dein json input). Egal, ob man die zeilenweise hat oder per join() zu einer Zeile zusammenbaut.


sub test{
  my $text = "{'ret_code': 0, 'ret_msg': 'OK', 'result': [{'user_id': 51101317, 'symbol': 'BTCUSDT', 'side': 'None', 'size': 0, 'position_value': 0, 'entry_price': 0, 'liq_price': 0, 'bust_price': 0, 'leverage': 1, 'auto_add_margin': 0, 'is_isolated': True, 'position_margin': 0, 'occ_closing_fee': 0, 'realised_pnl': -0.1473463, 'cum_realised_pnl': -0.2546504, 'free_qty': 0, 'tp_sl_mode': 'Full', 'unrealised_pnl': 0, 'deleverage_indicator': 0, 'risk_id': 1, 'stop_loss': 0, 'take_profit': 0, 'trailing_stop': 0, 'position_idx': 0, 'mode': 'MergedSingle'}], 'ext_code': '', 'ext_info': '', 'time_now': '1674316840.217231', 'rate_limit_status': 119, 'rate_limit': 120, 'rate_limit_reset_ms': 1674316840212}";
  $text =~ s/True/'True'/g;
  $text =~ s/False/'False'/g;
  $text =~ s/'/"/g;
  return Dumper json2nameValue($text);
}
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Stargazer

So langsam klickert es.

Ist trotzdem schwer, erstmal die Vorgehensweise heraus zu lesen.

ich habe jetzt folgendes, was dank Dir funktioniert:

sub test{
  my ($err,@input) = FileRead({FileName=>'/home/pi/BTCOrderInfoByBit.txt', ForceType=>'file'});
  return $err if $err;
  my $text = join ("",@input);
  $text =~ s/True/'True'/g;
  $text =~ s/False/'False'/g;
  $text =~ s/'/"/g;
  return Dumper json2nameValue($text);
}


Die Sache mit den Regex und dem testen, ist für mich trotzdem schwer. Warum ? Weil ich wahrscheinlich noch durch die $text Zuordnung verwirrt werde.
Ich habe sonst immer nur nach einem Schlüsselwort gesucht. Das hat immer so mit ach und krach funktioniert. Aber hier bin ich noch etwas verwirrt.

Das mit den Zusammenbauen aus dem Quelldaten, das ist mein Hauptproblem  :o

Vielen Dank bis hier her...

betateilchen

#20
Zitat von: Stargazer am 21 Januar 2023, 22:29:57
Die Sache mit den Regex und dem testen, ist für mich trotzdem schwer. Warum ? Weil ich wahrscheinlich noch durch die $text Zuordnung verwirrt werde.

Naja, Dein Hauptproblem ist vermutlich eher, dass Du noch nicht so einfach denken kannst, wie es eigentlich in Wirklichkeit ist.
Die Bearbeitung eines Variableninhaltes per regex ist nichts anderes als eine Rechenoperation mit einer Variablen.


my $zahl = 5;
   $zahl += 7;
   return $zahl;


Dass da 12 als Ergebnis kommt, wird Dich hoffentlich kaum verwundern.


Vergleichen wir das jetzt mit der Anwendung einer regex anstatt einer Addition:


my $text = "{'ret_code': 0, 'is_isolated': True}";
   $text =~ s/True/'True'/g;
   $text =~ s/False/'False'/g;
   $text =~ s/'/"/g;
   return $text;


Da kommt als Ergebnis

{"ret_code": 0, "is_isolated": "True"}

raus. Warum?

Der erste Schritt (my $text ...) ist hoffentlich noch klar.
Die nächsten drei Zeilen haben alle die gleiche Aufgabe: Sie sollen den Inhalt der Variablen $text verändern.
Konkret: Sie sollen im Inhalt der Variablen jeweils etwas anderes ersetzen.

s/<quelle>/<ziel>/g

Eine Standardsyntax einer regex, die man sich mit zwei Eselsbrücken gut merken kann.


  • s/ bedeutet suche und ersetze etwas.
  • /<quelle>/<ziel>/ bezeichnet WAS (<quelle>) gesucht werden soll und WOMIT (<ziel>) das Gefundene ersetzt werden soll.
  • /g bedeutet eigentlich "global", man kann sich das aber auch mit "gierig" merken: das ist der Parameter, der angibt, dass ALLE mit <quelle> gefundenen Stellen im Text ersetzt werden sollen und nicht nur die erste Fundstelle.

Damit solltest Du jetzt verstehen können, was in Deinem Code eigentlich wirklich passiert.


--
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Stargazer

Hallo betateilchen,

danke dir für die Erläuterungen. Doch ! Das lichtet schon einmal den dunklen "Regex-Schleier" etwas.

Nun habe ich noch ein kleines anderes Problem, mit den Rechten unter Linux.

Aber dazu mache ich einen anderen Thread auf.

VG

Stargazer

Hallo zusammen,
ich grabe dieses Thema noch einmal aus, da ich ein kleines Problem mit einem anderen JSON - Format habe.
Und zwar hat sich die Quelle der Abfrage geändert. Der Rest ist so geblieben. Es wird immer noch eine Datei ausgelesen, die den JSON - String beinhaltet.
Doch der wird vom Server nicht so ganz so sauber ausgeben. Leider. Es fehlen die Anführungszeichen im String, die der Server zurück gibt. Nur an einer Stelle.
Der String sieht wie folgt aus:

{"code": "00000", "msg": "success", "requestTime": 1728498144036, "data": [{"marginCoin": "USDT", "symbol": "WIFUSDT_UMCBL", "holdSide": "short", "openDelegateCount": "0", "margin": "62.355504233276", "available": "50", "locked": "0", "total": "50", "leverage": 2, "achievedProfits": "-1.251111111201", "averageOpenPrice": "2.478922222222", "marginMode": "fixed", "holdMode": "double_hold", "unrealizedPL": "6.6661111111", "liquidationPrice": "0", "keepMarginRate": "0.0066", "marketPrice": "2.3456", "marginRatio": None, "autoMargin": "off", "cTime": "1728405113909"}]}
Das Problem ist das, dass None am Ende des Strings nicht in Anführungszeichen steht. Darum ergibt die Abfrage auch "json2nameValueErrorText
error parsing (#2) 'None, "autoMargin": "off", "cTime": "1728405113909"'" seitens FHEM. Das ganze wird in dem DOIF - Modul als Readings zurück gegeben, welches auch die Abfrage via Python - Skript startet. Läuft wo anders im meinem System sehr gut. Nur hier macht er Probleme wegen zwei kleinen Anführungszeichen. Füge ich diese Manuell ein, habe ich alle Daten die brauche.

Kann mir jemand einen Tipp geben, wie ich den String richtig geparst bekomme. Theoretisch benötige ich die Daten noch nicht einmal, die ab "marginRatio" ausgegeben werden.

Vielen Dank für eure Mühe...

André

betateilchen

In der Datei das None per regex  ersetzen. Im einfachsten Falle durch zwei Anführungszeichen einen leeren String erzeugen.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Stargazer

Hallo betateilchen !

Okay. Das werde ich mal versuchen.

Dankeschön !


betateilchen

-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!