TwinCat3 Verständnisproblem TC3_JsonXML

jensemann

Level-2
Beiträge
284
Reaktionspunkte
109
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich stehe grade komplett auf der Leitung! Ich versuche, eine XML-Datei zu laden und die Daten in eine Struktur zu übertragen. Das Ganze funktioniert bereits mit FB_XmlSrvRead und der Versuch, über die JsonXML zu gehen, dient einem Geschwindigkeitsvergleich da in der Zukunft viele recht große Dateien geladen werden sollen.
Leider fehlt mir das Verständnis für den XMLDomParser wo ich mit der Methode LoadDocumentFromFile die XML lade, was offenbar passiert da sowohl die Startvariable als auch der Rückgabewert zurückgesetzt wird. Allerdings bekomme ich als XML-String nur '<?xml version="1.0"?>', egal was in der Datei steht.
Was übersehe ich?

Code:
Var

    fbXml : FB_XmlDomParser;
    xmlDoc : SXmlNode;
    sMessageToParse : T_maxstring;    
    xmlRootNode : SXmlNode;
    loaded : BOOL;    
    step : INT :=0;
    xmlLength : UDINT :=0;
    FTloaded : Tc2_Standard.F_TRIG;
End_Var
Code:
sFilePath := 'C:\Temp\test.xml' ;
FTloaded(CLK :=loaded);
CASE step OF
    0:  IF bstart2 THEN
            sMessageToParse := '';
            xmlLength := 0;
            fbxml.NewDocument();    
            step := step +1;
            
        END_IF
    
    1:
        loaded := fbxml.LoadDocumentFromFile(sFilePath,bstart2);
        IF FTloaded.Q THEN
            xmlRootNode := fbXml.GetRootNode();
            step := step +1;
            
         END_IF
    2:
        xmlLength := fbxml.CopyDocument(sMessageToParse,SIZEOF(GVL.Pos_ar));
        IF xmlLength > 0 THEN
            step := 0;
        END_IF
        
END_CASE

Anmerkung: GVL.Pos_ar ist das eigentliche Zielarry dessen Größe ich hier nur benutze um genügend Speicher zur Verfügung zu stellen.
xmlLength hat am Ende immer den Wert 22, sMessageToParse beinhaltet immer '<?xml version="1.0"?>'.

Wie komme ich an die XML-Daten?

Vielen Dank im Voraus
 
Es gibt Beispiele in der Doku die das Prinzip gut erklären (meine Meinung).
https://infosys.beckhoff.com/conten...sonxml/5529119243.html?id=6025266670169349274

Letztendlich lädt der Parser das Dokument nur in den Speicher. Über die verschiedenen Methoden wird dir dann die Möglichkeit gegeben in dem Datenstream nach Informationen zu suchen und diese zu lesen oder aber Daten einzufügen. Die < \> Syntax erfolgt versteckt im Hintergrund....

Wenn du häufiger Dateien hier liest würde ich zum Baustein DOMDYN raten. Funktioniert eigentlich identisch, gibt aber den Speicher frei.

Guga
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Genau bei den Beispielen komme ich ja auch nicht weiter. Dort wird das XMLDoc aus einem String gebildet und liefert einen 'SXmlNode'. Bei 'LoadDocumentFromFile' wird ein Bool zurückgeliefert und lässt mich dann damit allein. Versuche ich dann mit CopyDocument den String darzustellen, gibts nur '<?xml version="1.0"?>'. Das ist mir leider zu wenig und bei weitem nicht alles was in der Datei steht.
 
1. Die CopyDocument wird wahrscheinlich nicht ausgeführt weil sMessageToParse nur 255 Zeichen (T_maxstring) hat aber die XML Datei mehr Zeichen hat. Daher wird der Initialstring <?xml version="1.0"?> der Funktion nicht überschrieben.
Siehe Doku https://infosys.beckhoff.com/index....1031/tcplclib_tc3_jsonxml/5512100491.html&id=
"Beachten Sie, dass die Größe der String-Variablen mindestens der Größe des XML-Dokuments im DOM entspricht."
2. Den Schritt 0 mit fbxml.NewDocument(); benötigst du nicht.
 
Denn umweg über CopyDocument und ParseDocument kannst du dir sparen. Du bekommst mit GetRootNode bzw. GetDocumentNode oder FirstNodeByPath den ersten Node zurück.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
gelöscht.... alles gut

Kurze Info zur Löschung:

Ich möchte eine Json erstellen mit folgendem Format
JSON:
{
    "group" : {
        "subgroup" : {
            "parameter" : "42"
        }
    }   
}

Ich habe Probleme gehabt bei folgendem verkürztem Code:


Code:
VAR
    fbJson : FB_JsonDomParser;
    sJsonRoot :SJsonValue;
    sJsonValue : SJsonValue;
    strName    : STRING;
    bSave : BOOL := TRUE;
    bSaved : BOOL;
    sFile : STRING;
END_VAR

sJsonRoot := fbJson.NewDocument();

tmpName := 'group';
sJsonValue := fbJson.AddObjectMember(v := tmpJsonRoot,
                                       member := tmpName);
                                      
sName := 'subgroup';
sJsonValue := fbJson.AddObjectMember(v := tmpJsonValue,
                                       member := tmpName);
                                      
IF bSave THEN
    bSaved := fbJson.SaveDocumentToFile(sFile := sFile,
                                        bExec := bSave,
                                        hrErrorCode := hrResult);
END_IF

Ich hatte hier das Problem, dass eine leere Datei geschrieben wurde. Allerdings lag das bei mir am "drum herum" der nicht im Verkürzten Code steht.
 
Zuletzt bearbeitet:
Verständnisfrage: Ist die Struktur deines JSON-Objekts dynamisch?

Falls nein, könntest du Dir einfach mit AddJsonValueFromSymbol einen fertigen Json-Document-String erstellen lassen. Dessen Objektstruktur bildet 1:1 jene deines Symbols ab, egal wie komplex verschachtelt. Du würdest also einfach einen deinen Wünschen entsprechenden Struktur-Datentyp anlegen und dessen Symbol (Variable) beim Aufruf von AddJsonValueFromSymbol angeben. Zum Lesen, falls nötig, SetSymbolFromJson verwenden. Wenn du das ganze in einem unviersell für beliebige Datentypen verwendbaren FB gekapselt haben möchtest, kannst du sogar via GetDatatypeNameByAddress innerhalb eines FB den Datentyp des zu verarbeitenden Symbols automatisch ermitteln lassen (Symboladresse als Pointer vom Typ PVOID übergeben).
 
Die Struktur des Json-Objekts ist am Ende nicht dynamisch, also könnte ich AddJsonValueFromSymbol bzw. SetSymbolFromJson verwenden.

Falls ich den SaxReader / Writer verwenden würde, dann müsste ich den Json-String erst über den FB_JsonDomParser oder allgemein Datei-Reader bzw. Writer einlesen und in einem String speichern richtig?

Ich würde denke ich dennoch drauf verzichten, da ich die Daten aus Dateien lese und schreibe und diese möglicherweise doch händisch verpfuscht werden könnten. Ich möchte das nutzen um Einstellparameter zu exportieren / importieren.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wenn das JSON-File händisch verpfuscht wird bekommst du ja genauso einen Fehler beim lesen des "kaputten" Objekts. SetSymbolFromJson verhält sich übrigens so, dass wenn du die Strukturvariable in der PLC später mal erweiterst (z.b. wenn später mal eine neuer Einstellparameter dazu kommt), ein altes Json-File wo dieser noch fehlt dennoch gelesen und auf das PLC Symbol geschrieben wird.

Meine häufigste Nutzung ist die gleiche wie du beschreibst, das Exportieren/Importieren von Einstellungen. Ich nutze JSON aber auch als simpel integrierbare generische Rezeptverwaltung anstatt bei jeder neuen HMI-Lösung wieder was neues Konfigurieren/Programmieren zu müssen.

Falls du dir den Projektierungsaufwand sparen möchtest oder unter Zeitdruck bist, hätte ich Dir eine fertige Bibliothek mit diversen generischen JSON-Bausteinen. Darin enthalten ist bspw.:
1749633571458.png
 
Nur zur Info, der Post #1 ist etwas mehr als 4 Jahre alt. Mittlerweile weis ich schon gar nicht mehr, was ich damals programmiert habe aber ich bedanke mich trotzdem für die Mühe.

Viele Grüße
Jens
 
Achtung die TC3_JsonXML hat Probleme mit LREAL die auf .0 enden.

Der String der entsteht schneidet ".0" ab und beim zurück lesen kann diese Wert nicht gelesen werden.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Nur zur Info, der Post #1 ist etwas mehr als 4 Jahre alt. Mittlerweile weis ich schon gar nicht mehr, was ich damals programmiert habe aber ich bedanke mich trotzdem für die Mühe.

Viele Grüße
Jens
Jens, unsere neuen Feedbacks bezogen sich auf die Fragestellung von User MGL, der deinen alten Post mit seiner Frage "wiederbelebte" :)
 
Achtung die TC3_JsonXML hat Probleme mit LREAL die auf .0 enden.

Der String der entsteht schneidet ".0" ab und beim zurück lesen kann diese Wert nicht gelesen werden.

Hast du diese Erfahrung mit irgend einer Uralt-Version der Library gemacht?

Nutze diese Library jetzt schon eine ganze Weile und hatte das geschilderte Problem nie erlebt.

Screenshot eines mit der Library erstellten JSON-Files, wo grün eingekreist ein paar LREAL Variablen korrekt mit .0 gespeichert wurden und welches auch tadellos wieder gelesen wird:
1749673429778.png
 
Bei der Methode "AddJsonValueFromSymbol" in TwinCAT 4024.47 tritt dieses Phänomen auf und wurde mir vom Support bestätigt.
Wenn man die erzeugte JSON mit "SetSymbolFromJson" wieder zurücklesen möchte, dann funktioniert es nicht weil in der JSON dann ".0" fehlt.

Bei mir wurden alle Einstellwerte der Maschine in einem Struct gespeichert (persistent). Ich nutzte die Methoden, um eine „Backup/Restore“-Funktion zu erstellen. Das funktionierte so lange gut, bis in der Struktur LREAL Werte mit dem Wert „.0” auftauchten.

Vll. hat das Beckhoff ja gefixt. Aber erzählen werden die das ja niemanden ;)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Falls du dir den Projektierungsaufwand sparen möchtest oder unter Zeitdruck bist, hätte ich Dir eine fertige Bibliothek mit diversen generischen JSON-Bausteinen. Darin enthalten ist bspw.:
Anhang anzeigen 88220

Das wäre wirklich super, vielen Dank. Ich würde es mir auf jeden Fall gerne mal anschauen und eventuell übernehmen.
 
Zurück
Oben