XML und C++



  • Guten Morgen die Herrschaften, ich bin recht neu auf dem Gebiet von C++ und habe ein kleines Problem bei dem Ich Hilfe brauche.
    Ich muss Daten aus einer Messklemme in eine XML Datei schreiben. Ich habe dazu Beispielcode welcher auch wunderbar funktioniert, den ich aber nicht wirklich verstehe. Könnte mir evtl irgendjemand diesen Code erklären?
    Ich habe soviel verstanden, dass man array anlegt und diesen den Dateinamen und Pfad zuweist(aber warum?). Dann wird die XML Struktur definiert und danach die Datei Test1_tmp angelegt und zum schreiben geöffnet.
    Mir ist die nächste Zeile:

    sprintf(temp, xml, valueB, valueA, valueC);
    

    nicht ganz klar. Ich übergebe dem temp Array die Argumente value.....A-C? Und wie kommt mein XML ins Spiel?
    Die Zeile

    write(f, temp, strlen(temp));
    

    schreibt ja letztlich die Datei f welche ich geöffnet habe. Wozu wird temp gebraucht?

    Hier noch der ganze Code:

    char temp[1024];
                 char Test1_tmp[256]    = "/tmp/Test1_tmp.xml";
                 int f;
    
                 static const char xml[] =
    {                                                    
                 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
                 "<Werte>\n"
                 "<Werte id=\"1\" Spannung=\"%.2f\" Strom=\"%.2f\" Leistung=\"%.2f\"/>\n"
                 "</Werte>"
                 };
    
                 f = open(Test1_tmp, O_CREAT | O_WRONLY);                            
                 sprintf(temp, xml, valueB, valueA, valueC);
                 write(f, temp, strlen(temp));
    
                 close(f);
    

    Die Datei wird angelegt und es stehen auch Werte Darin. Alles so wie es sein soll. Mein nächstes Problem ist jedoch dass ich es nur schaffe einen Satz werte renzuschreiben. Wenn ich alles in eine Schleife setze, steht jeweils der letzte Satz Werte in der Datei, ich hätte jedoch gerne eine fortlaufende Liste.

    Ich wäre echt super dankbar wenn mir jemand den Code etwas erläutern würde und mir nen Tipp geben könnte wie ich mein Problem mit dem schreiben mehrerer Werte Lösen kann.

    Mfg Stefan



  • Such dir eine der vielen XML-libraries und nimm das.
    😉 rapidxml
    😉 pugixml
    😉 tinyxml
    😉 xerces-c
    😉 usw.



  • Für die open wirte und close Geschichte: klick mich

    sprintf funktioniert im großen und ganzen wie printf. Dass heißt du gibts einen format string (bei dir der char Array mit dem Namen xml) an, und dahinter die Werte, die geschrieben werden sollen. Der erste Parameter sagt, wo du hin schreiben willst(dein temp array).

    Für sprintf: klick mich.



  • oNes schrieb:

    Guten Morgen die Herrschaften, ich bin recht neu auf dem Gebiet von C++ und habe ein kleines Problem bei dem Ich Hilfe brauche.
    Ich muss Daten aus einer Messklemme in eine XML Datei schreiben. Ich habe dazu Beispielcode welcher auch wunderbar funktioniert, den ich aber nicht wirklich verstehe. Könnte mir evtl irgendjemand diesen Code erklären?

    Der Beispielcode ist wohl eher C.

    oNes schrieb:

    Ich habe soviel verstanden, dass man array anlegt und diesen den Dateinamen und Pfad zuweist(aber warum?). Dann wird die XML Struktur definiert und danach die Datei Test1_tmp angelegt und zum schreiben geöffnet.
    Mir ist die nächste Zeile:

    sprintf(temp, xml, valueB, valueA, valueC);
    

    nicht ganz klar. Ich übergebe dem temp Array die Argumente value.....A-C? Und wie kommt mein XML ins Spiel?

    Hier werden die Stellem mit %.2f in xml mit den Werten deiner value? Variablen gefüllt und nach temp geschrieben.

    oNes schrieb:

    Die Zeile

    write(f, temp, strlen(temp));
    

    schreibt ja letztlich die Datei f welche ich geöffnet habe. Wozu wird temp gebraucht?

    siehe oben, das Ergebnis wird halt in die Datei geschrieben.

    oNes schrieb:

    ...

    Die Datei wird angelegt und es stehen auch Werte Darin. Alles so wie es sein soll. Mein nächstes Problem ist jedoch dass ich es nur schaffe einen Satz werte renzuschreiben. Wenn ich alles in eine Schleife setze, steht jeweils der letzte Satz Werte in der Datei, ich hätte jedoch gerne eine fortlaufende Liste.

    Du musst das Schreiben zerlegen. Erst den Anfang (bis zum ersten "<Werte>\n"), dann in einer Schleife jeweils

    "<Werte id=\"1\" Spannung=\"%.2f\" Strom=\"%.2f\" Leistung=\"%.2f\"/>\n"
    

    (wobei du vermutlich auch die id ändern musst, oder?)

    und am Schluss das schließende "</Werte>". Dabei muss die Datei am Anfang einmal geöffnet und erst ganz am Schluss einmal geschlossen werden.

    Das ist aber primitiv-XML, wenn die Struktur komplexer wird ist das schwachsinnig.

    Lars



  • Danke für eure Antworten.

    @manni66: die id bleibt die gleiche, ich muss noch irgendwie nen Timestamp der Ausgelesenen Werte reinbasteln. Es geht einfach darum von einer Messklemme, bzw mehrerer Daten auszulesen und die in eine XML zu speichern.

    Ich habe mir jetzt mal tinyXml angeschaut und eingebunden. Nur damit komme ich auch nicht so wirklich weiter.

    mit:

    TiXmlDocument doc;
    
                    TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
                    doc.LinkEndChild( decl );
    
                    TiXmlElement * top = new TiXmlElement( "Werte" );
                    doc.LinkEndChild(top);
    
                    TiXmlElement * spng = new TiXmlElement( "Klemme_1" );
    
                    spng->SetDoubleAttribute("Spannung", valueA);
                    spng->SetDoubleAttribute("Strom", valueB);
    
                    top->LinkEndChild(spng);
                    doc.SaveFile( "/tmp/Test.xml" );
    

    bekomme ich wieder eine schöne Datei in der genau ein satz an werten steht. Ich hab den ganzen Code in einer schleife in der bei jeden durchlauf neue Werte(A u 😎 von der Klemme gehohlt werden. Ich möchte ja jetzt in jedem Durchlauf ein neues spng Element erzeugen. Wie kann ich das denn realisieren?

    Kennt jemand ein gutes Tutorial für TinyXml? Ich werde nicht so recht fündig und die Dokumentation erschlägt mich geradezu...



  • oNes schrieb:

    // erstelle ein dokument
       // erstelle einen knoten
       // adde den knoten
    // speichere dokument
    

    Du speicherst auch immer nur einen Wert (bzw alle 1WertDocumente in die selbe Datei).

    Versuchs so: [pseudocode]

    TiXmlElement * addElement(double valueA, double valueB)
    {
        TiXmlElement * klemme = new TiXmlElement( "Wert");
        klemme->SetDoubleAttribute("Spannung", valueA);
        klemme->SetDoubleAttribute("Stron", valueB); 
    
        return klemme;
    }
    
    // und da wo du Werte ausliest
    int main ()
    {
        TiXmlDocument doc;
    
        TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
        doc.LinkEndChild( decl );
    
        TiXmlElement * top = new TiXmlElement( "Messung" );
        doc.LinkEndChild( top );
    
        while (nichtFertigMitMessen)
        {
            warteAufNeuenWert();
    
            double Amp = getSpannungWieAuchImmer();
            double Volt = getStronWieAuchImmer();
    
            top->LinkEndChild( addElement(Amp,Volt) );
        } 
    
        doc.SaveFile( "/tmp/Test.xml" );
    

    Sprechende Bezeichner sind hilfreich, statt valueA/valueB nimm lieber strom, spannung, leistung wasauchimmer 🙂

    Im übrigen ist dein XML verbesserungswürding:

    <Werte>
        <Werte id ..../>
    </Werte>
    

    , liest sich besser als zB:

    <Messung Datum="...">
        <Wert timestamp="..."  id="...." usw./>
    </Messung>
    

    edit: paar sachen nachgeflegt



  • super, da werde ich mich morgen mal dran versuchen. Vielen Dank Aufjedenfall mal! sieht sehr vielversprechend aus.
    Das mit dem XML weiß ich;) aber man muss mir zugute halten dass ich mich erst seit drei Tagen damit beschäftige und auch sonst nicht der Profiprorgammierer bin.

    Nochmal zur Interpretation des ganzen: Die Funktion addElement() liefert "klemme" also die neu gesetzten Attribute an die aufrufende Funktion LinkEndChild()? Und mit top->Link... wird dann quasi die neue Zeile mit <Wert SpannungNeu....StromNeu...../> eingefügt?

    gruß,
    stefan



  • padreigh schrieb:

    Im übrigen ist dein XML verbesserungswürding:

    <Werte>
        <Werte id ..../>
    </Werte>
    

    , liest sich besser als zB:

    <Messung Datum="...">
        <Wert timestamp="..."  id="...." usw./>
    </Messung>
    

    Das ist absolut Geschmackssache. Ob ich das Eltternelement jetzt "Werte" nenne oder "Messung" ist wurscht. zweiteres signalisiert, dass es sich um gemessene Werte und nicht irgendwelche berechneten handelt, oder obs vllt. sogar Usereingaben sind. Und dass das Datum gleich bei der Messung dabeisteht ist auch von Vorteil, wenn man das Dokument durchsuchen will. Was zum Beispiel, wenn am einem Tag die Versuchsanordnung keine Ergebnisse messen konnte? Dann hab ich ein leeres <Werte>-Element, und weiß nicht von wann 😛

    Wenn an einem Tag mehrere Messreihen möglich sind, (die alle in dem XML landen) würde ich sogar noch mehr Unterteilungen und Attribute hinzufügen.



  • Hallo,

    XML ist veraltet, nimm JSON.



  • Das ist Käse.



  • oNes schrieb:

    Nochmal zur Interpretation des ganzen: Die Funktion addElement() liefert "klemme" also die neu gesetzten Attribute an die aufrufende Funktion LinkEndChild()? Und mit top->Link... wird dann quasi die neue Zeile mit <Wert SpannungNeu....StromNeu...../> eingefügt?

    Jupp, ich hab zwar nie was mit tinyXML gemacht 😉 aber so in etwa würde ich das versuchen. Es wirkt übersichtlicher sowas (Anlegen eines neuen Elementes, Adden von 2 double werten ) zu kapseln. Genau das macht addElement(double,double) : es nimmt deine beiden Werte entgegen, bastelt ein (in das xlm einzüfügendes) tinyXmlElement und liefert es zurück. Was top->LinkEndChild() macht, habe ich mal aus deinem Code (und dem Namen: LinkEndChild() == linke Ans Ende ein Child) vermutet (daher auch der Hinweis auf "Pseudocode" - ich hatte keine Lust in die tinyXML doku abzusteigen 😉 .

    Wenn du sowas (immer gleiches, mehrfach auszuführendes) in kleine Methoden kapselst wirkt es übersichtlicher (wobei so ein 3Zeiler mE ein Grenzfall ist - aber du willst ja vielleicht noch eine ID und einen Messzeitpunkt hinzufügen ... das brauchst du dann nur in der Methode zu machen und überall wo du die benutzt kommt dir das zu Gute ....

    TiXmlElement * addElement(double valueA, double valueB)
    {
        static static_ID = 0; // wird beim ersten aufruf auf 0 gesetzt, danach ignoriert
        klemme->SetIntegerAttribute("id", static_ID++); // schreibt den Wert rein, inkrementiert ihn dann (postinc)
        // usw weitere Attribute oder sogar unterelemente ;)
        TiXmlElement * klemme = new TiXmlElement( "Wert");
        klemme->SetDoubleAttribute("Spannung", valueA);
        klemme->SetDoubleAttribute("Stron", valueB);
    
        return klemme;
    }
    

    Ich hoffe nur das das TiXmlDocument doc zum Schluss all seine Kinder wieder freigibt, denn im Moment allocierst du Speicher ( T * name = new T() ) gibts den nie wieder frei ( delete name; ) - Ich vermute aber mal stark das das so ist.

    weissNimmerWer schrieb:

    jedes new braucht ein delete



  • Das ganze soll eigentlich so werden dass ich Leistungsdaten von Steckdosen in ne XML Packe. Da kommen noche ein Paar Werte dazu.. außerdem soll dass ganze möglichst Realtime geschehen. Ich weiß noch nicht ganz genau was der Controller hergibt, aber ich schätze mal pro Kanal locker 20 Werte die Minute und das ganze mit 3 Kanälen pro Klemme. Da kommt schon ganz gut was zusammen. Zumal es ingesamt 16 Klemmen werden sollen.. Ich werde das aufjedenfall in Methoden packen. Das wird ja sonst gigantisch.
    Ich muss nur erstmal rausbekommen wie wie es für eine Klemme mit einem Kanal geht. Dann kann ich das denke ich schon übertragen. Ich muss mich halt erstmal ordentlich einarbeiten.

    Werd morgen mal ein bischen probieren und früher oder später nochma posten weil ich nicht weiterkomme;)

    Bin echt dankbar für die Unterstützung! 👍 echt Klasse!



  • Ich wollte nur mal Rückmeldung geben das soweit alles ganz gut klappt mit dem Vorschlag den Du gemacht hattest padreigh.


Log in to reply