C/C++ Aus XML-String Kommazahlen extrahieren?



  • Hallo werte Gemeinde!

    Wie extrahiere ich am besten in C/C++ aus einem XML-Srting Kommazahlen und speichere sie gleich in eine Kommavariable zum Weiterrechnen? Der XML-String sieht zum Beispiel so aus:

    <Rob TYPE="KUKA">
    <RIst X=“12.6“ Y=“234.456“ Z=“645.79“ A=“2.4“ B=“456.814“ C=“65.33“ />
    <FTC Fx="1.234" Fy="54.75" Fz="345.76" Mx="2346.6" My="" Mz="3546" />
    <Override>90</Override>
    <IPOC>123645634563</IPOC>
    </Rob>

    Gruß, Matze



  • C/C++ gibts nicht! Nenn uns doch mal bitte eine real existierende Sprache, dann können wir dir auch weiter helfen.



  • Verzeihung! Ich meine dann C++. Und wie siehts damit aus?



  • Benutzt du irgend eine XML-Library? Z.B. TinyXML oder Xerces-C++? Falls nicht, wäre bei einfachen XML-Aufgaben TinyXML erstmal hilfreich. Dann mußt du den XML-Baum damit parsen lassen und dann kannst du die Strings konvertieren:

    std::stringstream s;
    s << ein_string; // der Zahlen-String aus dem geparsten XML.
    float zahl;
    s >> zahl;
    

    Wenn du keinen XML-Parser hast, wird das etwas mehr Code um den XML-String nach den Zahlen zu parsen. Weil einfach nur Anführungsstriche suchen, ist etwas blauäugig. Weniger blauäugig wäre Regex zum selber suchen zu benutzen. Aber dann kann man auch gleich nen XML-Parser nehmen. Und bei KUKA und Roboter hört sich das für mich nicht gerade nach Spielzeug an. 😉

    Ich hoffe konnte ein paar Tips geben.





  • Expat is an XML 1.0 parser written in C

    Der Fragesteller wollte aber C++.


  • Administrator

    XML Parser wurde ja schon genügend genannt, hier noch ein paar weitere Wege, wie man aus einem String eine Zahl bekommt:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-39488.html

    Grüssli



  • Danke Artchi!

    Ich hätte gedacht, dass es auch mit sscanf möglich wäre. Also irgendwie so ...

    sscanf(buffer, "<Rob TYPE="KUKA"><FTC Fx=\"" %d "Fy=\"" %d "Fz=\"" %d \""/></Rob>", fx, fy, fz);

    Naja, das mit den \" is oben nich ganz richtig, aber ich denke Du weißt, was ich meine.

    Gruß, Matze



  • Ja Dravere, diese Sachen hab ich auch schon woanders gelesen, aber ich möchte gerne Zahlen aus einem Text heraus konvertieren, welcher nicht nur aus Zahlen besteht, sondern auch aus Buchstaben etc. .



  • matze77! Dieses sscan-Ding ist... lass es mich milde ausdrücken: schlecht. 😉 Weil du dich ja damit auf genau diese eine bestimmte XML-Abfolge festlegst. Was ist wenn ein Zahlenwert fehlt? Was ist, wenn ein Value sich dazwischen schiebt? Dann geht mit deinem Konzept garnichts mehr. Und der Sinn von XML ist eigentlich das man flexibel Werte hinterlegt und entsprechend flexibel darauf reagieren können muß. Wenn du einen XML-Parser nimmst, macht er genau das: er liest flexibel ein und du kannst sagen, auf was für Inhalte du gerne reagieren willst.

    Du mußt natürlich den XML-Parser kennenlernen und dich darin einarbeiten, aber danach kannst du jedes XML-Dokument (nicht nur dieses ROBO-Beispiel) mit Leichtigkeit verarbeiten.

    Und damit das ganze schneller geht (das Einarbeiten), ist TinyXML nicht schlecht.



  • Artchi schrieb:

    matze77! Dieses sscan-Ding ist... lass es mich milde ausdrücken: schlecht. 😉 Weil du dich ja damit auf genau diese eine bestimmte XML-Abfolge festlegst. Was ist wenn ein Zahlenwert fehlt? Was ist, wenn ein Value sich dazwischen schiebt? Dann geht mit deinem Konzept garnichts mehr.

    Vielleicht reicht es ja für seinen Zweck. Immerhin besser, als gleich einen ganzen XML-Parser mitzuliefern.

    (Das Problem ist eher, dass %d eben für dezimale Ganzzahlen gedacht ist und nicht für Fließkommazahlen. Aber das ist ja nur ein Beispiel)

    Aber vielleicht wären RegEx ein bisschen praktischer, als ein Aufruf von sscanf.



  • Hey danke Artchi!

    Aber der XML-Rahmen ist absolut fest. Da ändert sich nichts. Der Robo schickt immer den gleichen XML-Rahmen. Nur die Zahlen ändern sich. Was meinst Du nun?



  • Also sscan würde ich pers. garnicht benutzen, weil ich das garnicht kenne. Scheint C zu sein, oder?

    TinyXML ist echt mini. Ist glaub ich auch nur Templates, muß man nicht mal bauen.

    Für Regex braucht man aber auch eine zus. Library, selbst wenn es nur TR1 ist. Oder haste TR1 oder Boost? Irgendwas muß man doch noch haben, kann mir nicht vorstellen, nur mit der Stdlib klar zu kommen. Oder ist das ne Embedded-Anwendung wo man auf jedes Byte achten muß?

    Wenns wirklich immer das gleiche Schema ist, dann kann man doch die Standard-Streams benutzen, oder? Funktionsweise ist ähnlich wie der obige Code, nur das man dann halt ne while-Schleife noch einbaut, und unwichtige Blöcke überspringt und mit der string-Klasse kann man ja unwichtige Infos wie =" und " entfernen, bevor die Zahl endgültig konvertiert wird.

    Möchte aber behaupten, das man bei dem Aufwand evtl. mit nem Parser schneller zum Ergebnis kommt. Aber kann man ja ausprobieren, dann weiß man es selber.

    Spirit wäre auch ne Möglichkeit. Aber auch eine zus. Library. Ich weiß nicht, ich bin halt eher der Typ, der sich lieber eine Library schnappt, wenns dafür was gibt. 😃



  • Joah, ich werd mir mal Boost besorgen und mit den RegExp rumexperimentieren! Danke Artchi!

    Aber die Sache mit sscanf interessiert mich dennoch, weil es sehr schlank und schnell ist, denke ich!



  • Wenn das Format immer fix ist, dann dürfte sscanf reichen. (Was aber nicht heißt, dass du dich nicht mal mit RegEx auseinandersetzen solltest :))

    @Artchi
    Regex sind im TR1 und der ist ja bei neuen Compilern dabei. Aber Boost würde ich auch nicht unbedingt als "extra Library" ansehen 😉



  • matze77 schrieb:

    Aber der XML-Rahmen ist absolut fest. Da ändert sich nichts.

    na denn...

    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    
    char *strings (char c)
    {
      static int state;
      static char buff[256];
      static char idx;
    
      switch (state)
      {
        case 0:
        if (c == '\"')
          state = 1;
        break;
    
        case 1:
        if (c == '\"')
        {
          buff[idx] = 0;
          state = 0;
          idx = 0;
          return buff;
        }
        buff[idx++] = c;
        break;
      }  
    
      return 0;
    }
    
    int main(void) 
    {
      char *xml =
        "<Rob TYPE=\"KUKA\">"
        "<RIst X=\"12.6\" Y=\"234.456\" Z=\"645.79\" A=\"2.4\" B=\"456.814\" C=\"65.33\" />"
        "<FTC Fx=\"1.234\" Fy=\"54.75\" Fz=\"345.76\" Mx=\"2346.6\" My=\"\" Mz=\"3546\" />"
        "<Override>90</Override>"
        "<IPOC>123645634563</IPOC>"
        "</Rob>";
    
      while (*xml)
      {
        char *p = strings (*xml++);
        if (p && (isdigit(*p) || *p==0))
        {
          printf ("%f\n", atof(p));
        }
      }     
    }
    

    🙂



  • das da oben: static char idx; ^^
    sollte ein 'int' sein, kein 'char'
    🙂



  • Boah! Danke Erst mal! Das muss ich mir erst mal in aller Ruhe anschauen.

    Aber ... Ich habs eben mal mit Dev-C++ kompiliert und er spuckt mir nur '12.6' aus, naja ok. Nur - der XML-Rahmen enthält ja, wenn empfangen wird, "echte" 🙂 Anfürhungszeichen ("). Im Code wurden diese durch (backslash") ersetzt und dann funktioniert es ja auch einigermaßen.

    Frage: Wird der Backslash automatisch generiert, wenn die Daten vom Netzwerk in den Buffer, Variable geschrieben werden? Ich glaub ja nich, mmmmhh .... Wenn nicht, dann werd ich wohl nich um die RegEx drumrumkommen, oder?



  • die backslashes braucht man nur, wenn man "'s in stringkonstanten im code hat. im speicher sind sie nicht mehr vorhanden.

    char *cp = "12\\34\"56\"";  // <-- im speicher steht dann [b]12\34"56"[/b] die beiden äusseren "'s sind die begrenzungen des string-literals
    

    der code^^ reagiert übrigens auf "'s und nicht auf \'s. funktioniert er unverändert bei dir?
    🙂



  • Nein, ich hab noch char in int umgeschrieben, so wie feuerteufel-Fan es schrieb. Aber dann spuckt er mir auch nur 12.6 aus. Ich finde den Code von ihm ein weinig zu überdimensioniert. Da hab ich selbst mal was probiert ...

    /* sscanf example */
    #include <stdio.h>
    
    int main ()
    {
      char sentence []="<FTC Fx=\"1.234\" Fy=\"54.75\"";
      float x, y;
    
      sscanf (sentence,"<FTC Fx=\"%f\" Fy=\"%f\"",&x, &y);
      printf ("%f, %f\n",x,y);
      getchar();
    
      return 0;
    }
    

    Ausgabe: 1.234000, 54.750000

    Und das ist auch genau was ich erstmal möchte nur das mir die Anführungszeichen in der Quelle (sentence) noch Sorgen machen.

    Also Du meinst, dass was im Spiecher liegt (sentence) sind ganz normale ("). Ich muss nur noch wissen, was genau in sentence drinne steht und dann kann ich mit

    sscanf(sentence, "XML-Rahmen mit Kommazahlen in Anführungszeichen", &x, &y);
    

    die Kommazahlen auslesen, oder? Ich muss nur die Anführungszeichen im XML-Code bei sscanf als (backlash") eingeben und dann liest sscanf die Kommazahlen korrekt aus dem NetzwerkEmpfangspuffer aus, oder?


Anmelden zum Antworten