xml-Datei durchsuchen und ggf. mehrere Zeilen löschen



  • Hallo Leute,

    ich hatte bis jetzt noch nichts mit dem Einlesen von Dateien zu tun, deswegen habe ich hier ein paar Fragen. Also ich habe eine xml-Datei und ich muss in einem bestimmten Bereich zwischen zwei Tags mehrere Zeilen löschen.

    z.B. zwischen diesen Tags sind mehrere Zeilen ---> <Beispiel> </Beispiel>

    <Beispiel>
    Zeile1
    Zeile2
    Zeile3
    Zeile4
    </Beispiel>

    So jetzt meine Fragen.

    1. Wie lese ich z.B. eine xml-Datei ein. Wird die eingelesene Datei in irgendeiner Variablen gespeichert ? Wenn ja welchen Datentyp muss ich wählen ? String ?
    2. Ich muss ja einmal nach diesem Tag suchen "<Beispiel>" und einmal nach diesem "</Beispiel>". Wie finde ich nun heraus wieviele Zeilen dazwischen sind bzw. wie ich die Zeile löschen kann.


  • ich kann auch die xml datei in eine textdatei umwandeln. wäre egal



  • Hallo

    Zwei Möglichkeiten :
    - Die XML-Datei im normalen Textmodus mit std::ifstream öffnen und Zeilenweise einlesen (std::getline, std::string). Dann kannst du zuerst die Zeile mit dem Anfangstag suchen, und davon ausgehend die mit dem Endtag. Dann must du den gesamten Inhalt wieder speichern, dabei den gefundenen Bereich aber auslassen

    - Du verwendest eine externe XML-Library (tinyXML), um das Laden, Parsen und Speichern übernehmen zu lassen. Die Library bietet sicher auch Methoden zum Suchen und Löschen an, bestehend auf den Datenstrukturen die die Libraray ausgibt.

    bis bald
    akari



  • Wo bekomme ich denn genau Informationen auf "deutsch" zu "std::ifstream" etc pp.
    Ist das schon objektorientiert ? Mir fehlt es ja schon fast an grundlegenden Sachen, ich habe aber leider nicht viel Zeit.



  • Die meisten Dokumentationen zu den IO-Streams sind auf Englisch (überhaupt wirst du noch oft in die Situation kommen, dich mit englischen Erläuterungen herumschlagen zu müssen). Wenn du einen deutschen Einstieg benötigst, schau mal in unser Magazin.

    PS: die IO-Streams sind im weitesten Sinne schon objektorientiert. Aber inwieweit sich das auf dein Design auswirkt, ist die andere Frage 😉

    (ich würde wohl eine eigene Klasse XML-Element anlegen, die den Tag-Namen und eine Liste der Kind-Elemente selber verwaltet)



  • Hallo Leute ich bins nochmal,

    also noch einmal zu meinem Problem zurück. Bin ja newbie.
    Also ich weiß wie ich auf Parameter zugreife, die ich beim Programmaufruf mitgebe. Das habe ich rausbekommen.

    Mein Problem: ist aber immer noch in einer Datei nach etwas zu suchen (Suchbegriff steht in einer Variablen) und wenn der Suchbegriff gefunden wird bis zu einer stelle Sachen zu löschen. Diese Stelle bis wohin gelöscht werden soll steht in einer anderen Variablen.

    Also ich kann eine Datei öffnen, und in der Konsole den Dateiinhalt meiner Textdatei auszugeben.

    int main(int argc, char* argv[])
    {
      ifstream datei;											// neues objekt zum auslesen meiner datei
      string zeile;											 // ein string in den eine zeile immer geschrieben wird
      datei.open("Configuration.txt", ios::in);		         // öffnen der datei + zuweisung in objekt
      while(!datei.eof())									   // bis end of file
      {
    	getline(datei,zeile);								   //hol die nächste zeile
    	cout << zeile << endl;
      }
      datei.close();
      getch();
      return 0;
    }
    


  • Suchen in Strings kannst du mit der Methode find() - und auf dieser Basis entscheiden, ob du die Daten ausgeben willst:

    int main(int argc, char* argv[])
    {
      ifstream datei;
      string zeile;
      datei.open("Configuration.txt", ios::in);
    
      string start="<Beispiel>",ende="</Beispiel>";//Start und Ende der zu überspringenden Sequenz
      bool ign=false;
    
      while(!datei.eof())
      {
        getline(datei,zeile);
        if(zeile.find(start)!=string::npos) ign=true; //Blockanfang gefunden
        if(zeile.find(ende) !=string::npos) ign=false;//Blockende gefunden
    
        if(!ign) cout << zeile << endl;
      }
      datei.close();
      getch();
      return 0;
    }
    

    (das lässt sich sicher noch optimieren, aber das Grundprinzip sollte klar sein)



  • Was bedeutet dies Abfrage auf ungleich hier:
    (zeile.find(start)!=string::npos)

    Also das Programm funktioniert jetzt dank dir schon soweit das fast alles korrekt ausgegeben wird. Nur die letzte Zeile also die Zeile mit --->

    </Beispiel>

    wird noch ausgegeben. Mal gucken.

    Ich habe in der Schule sage ich mal angefangen C++ zu lernen. Aber nie richtig objektorientiert programmiert. (meine Kentnisse: Array,Schleifen,Funktionen sowas)
    Bei Klassen habe ich extreme Probleme. Wo kann ich mir denn z.b. angucken welche Methoden ein Objekt von "fstream" hat, oder welche Methoden ich von "strings" aufrufen kann. Z.b. dein "find".

    Selbst das mit Zeigern "char* argv[]" ist für mich nicht richtig klar.
    Also das was in meinem "main" oben bei der Parameterübergabe steht.

    CStoll schrieb:

    Suchen in Strings kannst du mit der Methode find() - und auf dieser Basis entscheiden, ob du die Daten ausgeben willst:

    int main(int argc, char* argv[])
    {
      ifstream datei;
      string zeile;
      datei.open("Configuration.txt", ios::in);
    
      string start="<Beispiel>",ende="</Beispiel>";//Start und Ende der zu überspringenden Sequenz
      bool ign=false;
    
      while(!datei.eof())
      {
        getline(datei,zeile);
        if(zeile.find(start)!=string::npos) ign=true; //Blockanfang gefunden
        if(zeile.find(ende) !=string::npos) ign=false;//Blockende gefunden
    
        if(!ign) cout << zeile << endl;
      }
      datei.close();
      getch();
      return 0;
    }
    

    (das lässt sich sicher noch optimieren, aber das Grundprinzip sollte klar sein)



  • hustle1 schrieb:

    Was bedeutet dies Abfrage auf ungleich hier:
    (zeile.find(start)!=string::npos)

    find() liefert die Position zurück, an der es den Suchstring gefunden hat, oder den vordefinierten Wert 'npos' für "nicht gefunden" - das bedeutet, daß die if()-Anweisung ausgeführt wird, wenn der String gefunden wurde.

    Also das Programm funktioniert jetzt dank dir schon soweit das fast alles korrekt ausgegeben wird. Nur die letzte Zeile also die Zeile mit --->

    </Beispiel>

    wird noch ausgegeben. Mal gucken.

    Da könnte es schon ausreichen, wenn du die if()s vertauschst.

    Bei Klassen habe ich extreme Probleme. Wo kann ich mir denn z.b. angucken welche Methoden ein Objekt von "fstream" hat, oder welche Methoden ich von "strings" aufrufen kann. Z.b. dein "find".

    Recht gute Hilfestellung findest du in der MSDN, unter www.cppreference.com oder auch in meinen Magazin-Artikeln (auch wenn du da etwas länger suchen mußt).

    Selbst das mit Zeigern "char* argv[]" ist für mich nicht richtig klar.
    Also das was in meinem "main" oben bei der Parameterübergabe steht.

    argc und argv enthalten die Parameter, mit denen dein Programm aufgerufen wurde (argc ist die Anzahl, argv[0] idR der Programmname, argv[1] bis argv[argc] die weiteren Parameter).



  • Mein Problem ist nun wenn ich das Programm laufen lasse, ist zwar eine neue korrekte xml datei erstellt worden. Also korrekt vom Inhalt. Die Datei wurde im ANSI-Format abgespeichert und deshalb sagt mir z.B. der IE einen Fehler beim Aufruf der Datei. Wenn ich Notepad öffne und in der UTF-8 Codierung abspeicher, und anschließend die Datei aufrufe, stellt sie der IE ohne Fehler korrekt da.

    Für Leute die es mal gebrauchen können:
    z.B. Aufruf des Programmes in der Eingabeaufforderung

    euerprogrammname.exe eure_zu_durchsuchende_datei.xml "begin" "ende"

    int main(int argc, char* argv[])
    {
      ifstream datei;
      ofstream neuedatei;
      string zeile;
    
      datei.open(argv[1], ios::in);
      neuedatei.open("temp.xml", ios::in);
    
      bool gefunden = false;
    
      while(!datei.eof())
      {
        getline(datei,zeile);
        if(zeile.find(argv[2])!=string::npos) 
          gefunden = true;
        if(!gefunden)
          neuedatei << zeile << endl;
        if(zeile.find(argv[3]) !=string::npos) 
          gefunden = false;
      }
    
      datei.close();
      neuedatei.close();
      remove(argv[1]);
      rename("temp.xml", argv[1]);
      return 0;
    }
    


  • Also den Fehler mußt du nochmal genauer erklären. Was für einen Fehler meldet der IE?

    hustle1 schrieb:

    neuedatei.open("temp.xml", ios::in);

    Sollte die Ausgabedatei nicht besser im Modus ios::out geöffnet werden?



  • Selbstverständlich mit "ios:out"
    habe es nur abgesprieben gehabt, da ich auf nem privaten laptop das programm geschrieben habe, aber nur an einem anderen rechner i net habe.
    deswegen der fehler beim abschreiben.
    kann leider nicht als hustle1 editieren.

    Fehler im IE:

    Die XML-Seite kann nicht angezeigt werden
    Die XML-Eingabe kann nicht angezeigt werden, wenn Stylesheet XSL verwendet wird. Beheben Sie den Fehler und klicken Sie dann auf Aktualisieren, oder wiederholen Sie den Vorgang später.

    --------------------------------------------------------------------------------

    Ungültig auf der obersten Ebene im Dokument. Fehler beim Bearbeiten der Ressource 'file:///C:/Downloads/Programm/Filters.xm...

    </Filters>

    Kaputte Datei http://home.arcor.de/hustle.on.1/Filters.xml
    Die Datei enthält nach dem Löschen mit meinem Programm komische Zeichen. Mit nem Editor siehste die.

    Wenn ich eine xml Datei, die sich im IE öffnen lässt, anschließend im Notepad öffne und mit der ANSI Codierung abspeichere, lässt sie sich trotzdem noch öffnen. Also es liegt es dann anscheinend nicht an der Codierung ANSI/UTF-8, sondern an diesen Zeichen (Return ?)



  • *Push* *Push*

    Jemand eine Ahnung zu meinem oben genannten Problem ?

    CStoll ?



  • hustle schrieb:

    *Push* *Push*

    Jemand eine Ahnung zu meinem oben genannten Problem ?

    CStoll ?

    *Push*



  • hustle schrieb:

    Jemand eine Ahnung zu meinem oben genannten Problem ?

    CStoll ?

    Sorry, hier muß ich passen - mit C++ kenne ich mich aus, aber dein Problem scheint XML zu betreffen und das ist nicht mein Fall.



  • CStoll schrieb:

    hustle schrieb:

    Jemand eine Ahnung zu meinem oben genannten Problem ?

    CStoll ?

    Sorry, hier muß ich passen - mit C++ kenne ich mich aus, aber dein Problem scheint XML zu betreffen und das ist nicht mein Fall.

    Ich habe nun aber wieder ein C++ Problem nachdem ich das XML Problem gelöst habe.
    Lösung: Anstatt Borland Builder 5 den 6er genommen.
    Ich weiß nicht warum es mit dem 6er geht !! Habe exakt den gleichen Code verwendet !!!
    So nun zu meinem problem:

    wenn ich mein programm aufrufe. und ihm einen xml-tag (Parameter 2) mitgebe, der so aussieht:

    <config mode="hallo">

    dann verändert er mir meine datei nicht. Sie ist aber weiterhin okay.
    Der Parameter 3 wäre dann z.b. dieser:

    </config>

    Ich weiß auch woran das Problem liegt und zwar, überall da wo in meinem Code auf diesen zweiten Parameter zugegriffen wird mit "argv[2]" wird aus

    <config mode="hallo"> ----> <config mode=>

    Also er schließt, dass was innerhalb meiner Gänßefüßchen ist aus. Der Tag "<config mode=>" wird natürlich nicht in meiner übergebenen XML-Datei gefunden.

    #include <iostream.h>
    #include <fstream>
    #include <conio.h>
    using namespace std;
    
    void main(int argc, char* argv[])
    {
      ifstream datei, temp;
      ofstream neuedatei;
      string zeile, parameter, zeilenanzahlstring;
      int pos1, pos2, abstand, parameterlaenge;
    
      if(argc == 4)
      {
    
        datei.open(argv[1], ios::in);
        neuedatei.open("temp.xml", ios::out);
    
        while(getline(datei, zeilenanzahlstring))
          neuedatei << zeilenanzahlstring;
    
        datei.close();
        neuedatei.close();
        remove(argv[1]);
        rename("temp.xml", argv[1]);
    
        temp.open(argv[1], ios::in);
        neuedatei.open("temp.xml", ios::out);
    
        parameter = argv[3];
        parameterlaenge = parameter.length();
    
        getline(temp,zeile);
        while(zeile.find(argv[2]) != string::npos)
        {
          pos1 = zeile.find(argv[2]);
          pos2 = zeile.find(argv[3]);
          pos2 += parameterlaenge;
          abstand = pos2-pos1;
          zeile.erase(pos1, abstand);
        }
        neuedatei << zeile;
    
        temp.close();
        neuedatei.close();
    
        remove(argv[1]); 
        rename("temp.xml", argv[1]);
      }
    }
    

    Das doppelte Öffnen, Schließen, Löschen und Umbennen passiert aus folgendem Grund und zwar lösch ich beim ersten mal alle zeilenumbrüche und beim zweiten mal, also zugriff auf die datei per "getline()" hole ich mir nur eine Zeile aus der Datei. Hat in meinem Fall paar Probleme deshalb diese Lösung!!!



  • hustle schrieb:

    CStoll schrieb:

    hustle schrieb:

    Jemand eine Ahnung zu meinem oben genannten Problem ?

    CStoll ?

    Sorry, hier muß ich passen - mit C++ kenne ich mich aus, aber dein Problem scheint XML zu betreffen und das ist nicht mein Fall.

    Ich habe nun aber wieder ein C++ Problem nachdem ich das XML Problem gelöst habe.
    Lösung: Anstatt Borland Builder 5 den 6er genommen.
    Ich weiß nicht warum es mit dem 6er geht !! Habe exakt den gleichen Code verwendet !!!
    So nun zu meinem problem:

    wenn ich mein programm aufrufe. und ihm einen xml-tag (Parameter 2) mitgebe, der so aussieht:

    <config mode="hallo">

    dann verändert er mir meine datei nicht. Sie ist aber weiterhin okay.
    Der Parameter 3 wäre dann z.b. dieser:

    </config>

    Ich weiß auch woran das Problem liegt und zwar, überall da wo in meinem Code auf diesen zweiten Parameter zugegriffen wird mit "argv[2]" wird aus

    <config mode="hallo"> ----> <config mode=>

    Also er schließt, dass was innerhalb meiner Gänßefüßchen ist aus. Der Tag "<config mode=>" wird natürlich nicht in meiner übergebenen XML-Datei gefunden.

    #include <iostream.h>
    #include <fstream>
    #include <conio.h>
    using namespace std;
    
    void main(int argc, char* argv[])
    {
      ifstream datei, temp;
      ofstream neuedatei;
      string zeile, parameter, zeilenanzahlstring;
      int pos1, pos2, abstand, parameterlaenge;
    
      if(argc == 4)
      {
    
        datei.open(argv[1], ios::in);
        neuedatei.open("temp.xml", ios::out);
    
        while(getline(datei, zeilenanzahlstring))
          neuedatei << zeilenanzahlstring;
    
        datei.close();
        neuedatei.close();
        remove(argv[1]);
        rename("temp.xml", argv[1]);
    
        temp.open(argv[1], ios::in);
        neuedatei.open("temp.xml", ios::out);
    
        parameter = argv[3];
        parameterlaenge = parameter.length();
    
        getline(temp,zeile);
        while(zeile.find(argv[2]) != string::npos)
        {
          pos1 = zeile.find(argv[2]);
          pos2 = zeile.find(argv[3]);
          pos2 += parameterlaenge;
          abstand = pos2-pos1;
          zeile.erase(pos1, abstand);
        }
        neuedatei << zeile;
    
        temp.close();
        neuedatei.close();
    
        remove(argv[1]); 
        rename("temp.xml", argv[1]);
      }
    }
    

    Das doppelte Öffnen, Schließen, Löschen und Umbennen passiert aus folgendem Grund und zwar lösch ich beim ersten mal alle zeilenumbrüche und beim zweiten mal, also zugriff auf die datei per "getline()" hole ich mir nur eine Zeile aus der Datei. Hat in meinem Fall paar Probleme deshalb diese Lösung!!!

    *Push Push*

    Geht doch eigentlich im Prinzip nur, wie ich selbst Gänßefüßchen in einer Variablen abspeichere:

    AnsiString NamederVar = " Hallo" benjamin" ";
    Variablentyp ist in meinem Fall halt:

    char* argv[]

    Wenn es damit nicht geht, weiß vielleicht jemand eine Möglichkeit wie ich es hinbekomme, Parameter, die Gänßefüßchen enthalten zu übergeben und mit denen weiterzuarbeiten?



  • Naja, das liegt in diesem Fall nicht am Datentyp und generell nicht bei C++. Es ist eine Frage des Betriebssystems, mitunter auch der shell, wie sie Parameter übergibt bzw. wie es die Eingabe parst. Frag' mich aber bitte jetzt nich wie diese komische Windows/DOS Krücke "cmd.exe" (%ComSpec%, %SystemRoot%\system32\cmd.exe) das macht...

    Greetz, Swordfish

    *edit: to sophisticated*



  • einfach ein backslash vors Gänsefüßchen!
    Thread kann geclosed werden.

    Big Thx 4 Help @ all


Log in to reply