Anwendung: verwirrender Fehler bei XML - Datei



  • Hallo!

    Zuerst schonmal:
    Ja, ich habe die FAQ gelesen, und die Borland Hilfe und TROTZDEM hänge ich seit 2 Tagen über dem Problem:
    Ich möchte einige Einstellungen aus meinem Programm in eine XML Datei speichern. Diese wird bei Bedarf, wenn sie noch nicht existiert, erstellt.
    Klappt auch alles.
    Dann übergebe ich meiner XML-Funktion einen String, z.b.: "Hallo\\das\\ist\\ein\\test". In der XML Datei soll dann dies stehen:

    <Hallo>
       <das>
          <ist>
            ....
               <Eintrag1>1</Eintrag1>
               <Eintrag2>1</Eintrag2>
               <Eintrag3>1</Eintrag3>
            .... 
          </ist>
       </das>
    </Hallo>
    

    Das macht er auch...ABER..
    wenn ich nun Werte einfügen will, dann Schreibt er die Einträge hintereinander, nicht untereinander (d.h. er schreibt kein newline in die XML Datei).

    <Hallo>
       <das>
          <ist>
            ....
               <Eintrag1>1</Eintrag1><Eintrag2>1</Eintrag2><Eintrag3>1</Eintrag3>
            .... 
          </ist>
       </das>
    </Hallo>
    

    Das heißt ja im Prinzip, dass irgendwo im Code ein Fehler ist.
    Hier der Copy-Paste Code zum selber Probieren:

    Ich würde mich über eine Rückmeldung freuen!

    XML.cpp:

    #include <vcl.h>
    #include <string>
    #pragma hdrstop
    
    #include "XML.hpp"
    
    using namespace std;
    
    //---------------------------------------------------------------------------
    // XML - Datei speichern / anlegen
    //---------------------------------------------------------------------------
    bool SaveXMLOption(string FileName, string XMLString, string ChildContent)
    {
    int count=GetXMLNote(XMLString,0).count;
    _di_IXMLNode tempKnoten1,tempKnoten2;
    
    NoteInfoStrukt tempNoteInfo =GetXMLNote(XMLString,1);
    
    if(XMLString=="")  // XMLString darf nicht leer sein
    return false;
    
     if(FileExists(FileName.c_str()))
      {
        try
        {
           _di_IXMLDocument XMLDocument = LoadXMLDocument(FileName.c_str());
          XMLDocument->Active = true;
          tempKnoten1 = XMLDocument->DocumentElement;
        for(int i=2;i<count;i++)
       {
       if(i%2)
       {
        if(tempKnoten2->ChildNodes->FindNode((tempNoteInfo = GetXMLNote(XMLString,i)).Node.c_str())==NULL)
        tempKnoten1 = tempKnoten2->AddChild(tempNoteInfo.Node.c_str());
        else
        tempKnoten1 =  tempKnoten2->ChildNodes->FindNode((tempNoteInfo = GetXMLNote(XMLString,i)).Node.c_str());
          }
       else
        {
        if(tempKnoten1->ChildNodes->FindNode((tempNoteInfo = GetXMLNote(XMLString,i)).Node.c_str())==NULL)
        tempKnoten2 = tempKnoten1->AddChild((tempNoteInfo =GetXMLNote(XMLString,i)).Node.c_str());
        else
          tempKnoten2 =  tempKnoten1->ChildNodes->FindNode((tempNoteInfo = GetXMLNote(XMLString,i)).Node.c_str());
          }
       }
       if(count%2)
       if(tempKnoten2->ChildNodes->FindNode((tempNoteInfo = GetXMLNote(XMLString,count)).Node.c_str())!=NULL)
        tempKnoten2->ChildNodes->Delete((tempNoteInfo = GetXMLNote(XMLString,count)).Node.c_str());
       else
       if(tempKnoten1->ChildNodes->FindNode((tempNoteInfo = GetXMLNote(XMLString,count)).Node.c_str())!=NULL)
        tempKnoten1->ChildNodes->Delete((tempNoteInfo = GetXMLNote(XMLString,count)).Node.c_str());
    
       _di_IXMLNode Node = XMLDocument->CreateElement((tempNoteInfo =GetXMLNote(XMLString,count)).Node.c_str(), L"");
       Node->NodeValue = WideString(ChildContent.c_str());
       if(count%2)
        tempKnoten2->ChildNodes->Add(Node);
       else
        tempKnoten1->ChildNodes->Add(Node);
    
        // XML Dokument in eine Datei abspeichern
        XMLDocument->FileName=FileName.c_str();
        XMLDocument->SaveToFile(XMLDocument->FileName);
      }
        catch (...){
      return false; }
    
      return true;
      }
      else
      {
       try
        {
    
    TXMLDocument *XMLDocument = new TXMLDocument(""); // WICHTIG: kein Datei Namen übergeben, sonst Exception
    
    XMLDocument->Options = XMLDocument->Options << doNodeAutoIndent;  // für die richtige Formatierung
    XMLDocument->Active = true;
    XMLDocument->Encoding = "UTF-16";    // Encoding festlegen, damit auch z.B. Umlauten richtig rüberkommen
    XMLDocument->FileName=FileName.c_str();
    
    tempKnoten1 = XMLDocument->CreateElement((tempNoteInfo =GetXMLNote(XMLString,1)).Node.c_str(), "");
    XMLDocument->DocumentElement = tempKnoten1;
    
       for(int i=2;i<count;i++)
       {
       if(i%2)
        if(tempKnoten2->ChildNodes->FindNode((tempNoteInfo = GetXMLNote(XMLString,i)).Node.c_str())==NULL)
        tempKnoten1 = tempKnoten2->AddChild(tempNoteInfo.Node.c_str());
        else
          tempKnoten1 =  tempKnoten2->ChildNodes->FindNode((tempNoteInfo = GetXMLNote(XMLString,i)).Node.c_str());
       else
        if(tempKnoten1->ChildNodes->FindNode((tempNoteInfo = GetXMLNote(XMLString,i)).Node.c_str())==NULL)
        tempKnoten2 = tempKnoten1->AddChild((tempNoteInfo =GetXMLNote(XMLString,i)).Node.c_str());
        else
          tempKnoten2 =  tempKnoten1->ChildNodes->FindNode((tempNoteInfo = GetXMLNote(XMLString,i)).Node.c_str());
       }
       _di_IXMLNode Node = XMLDocument->CreateElement((tempNoteInfo =GetXMLNote(XMLString,count)).Node.c_str(), L"");
       Node->NodeValue = WideString(ChildContent.c_str());
       if(count%2)
        tempKnoten2->ChildNodes->Add(Node);
        else
        tempKnoten1->ChildNodes->Add(Node);
    
        // XML Dokument in eine Datei abspeichern
        XMLDocument->SaveToFile();
      }
      catch (...)
      {
       return false;
      }
    
      return true;
      }
    }
    //---------------------------------------------------------------------------
    
    //---------------------------------------------------------------------------
    // XML - Knoten rausfiltern
    //---------------------------------------------------------------------------
    NoteInfoStrukt GetXMLNote(string XMLString, int index)
    {
     NoteInfoStrukt myNoteInfo;
    
     int tempIndex=0;
     int count=0;
     string tempString=XMLString;
    
     myNoteInfo.Node="";
    
     while((tempIndex=tempString.find("\\"))>=0)
     {
     if(count==0)
     count++;
     count++;
     tempString=tempString.substr(tempIndex+1);
     }
    
     tempString = XMLString;
    
     if((index<=count)&&(index>0))
     {
     for(int i=0; i<index;i++)
     {
      if(index<count)
     myNoteInfo.Node=tempString.substr(0,tempString.find("\\"));
     else
     myNoteInfo.Node=tempString;
     tempString=tempString.substr(tempString.find("\\")+1);
     }
     }
    
     myNoteInfo.count=count; // Gesamtanzahl an Argumente zurückgeben
    
     return myNoteInfo;
    }
    

    XML.hpp:

    #ifndef XMLH
    #define XMLH
    //---------------------------------------------------------------------------
    //
    // XML - Header Datei
    //
    // Funktionen:
    //
    //  bool SaveProfileOption(string , string , string ) 
    //
    //
    //---------------------------------------------------------------------------
    //
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    #include <ExtCtrls.hpp>
    #include "CSPIN.h"
    #include <Graphics.hpp>
    #include <oxmldom.hpp>
    #include <XMLDoc.hpp>
    #include <xmldom.hpp>
    #include <XMLIntf.hpp>
    
    #include <string>
    
    //
    //---------------------------------------------------------------------------
    using namespace std;
    
    struct NoteInfoStrukt {
     int count;
     string Node;
    };
    
    bool SaveXMLOption(string FileName, string XMLString, string ChildContent);
    NoteInfoStrukt GetXMLNote(string XMLString, int index);
    
    #endif
    

    Unit123.cpp:

    #include "XML.hpp"
    
    .....
    
    SaveXMLOption("profile.xml","Haupt\\Unterpunkt\\Menu\\Schritt1", "Test1");
    SaveXMLOption("profile.xml","Haupt\\Unterpunkt\\Menu\\Schritt2", "Test2");
    SaveXMLOption("profile.xml","Haupt\\Unterpunkt\\Menu\\Schritt3", "Test3");
    


  • Was mir jetzt spontan auffällt, ist, dass die Zeile

    XMLDocument->Options = XMLDocument->Options << doNodeAutoIndent;  // für die richtige Formatierung
    

    nur dann ausgeführt wird, wenn die Datei neu angelegt wird.
    Vielleicht solltest Du Dir auch mal überlegen, den Code etwas übersichtlicher zu gestalten und zu kommentieren.
    Von der Vorgehensweise her würde ich erstmal dafür sorgen eine gültige XMLDocument-Instanz zu haben, d.h. entweder eine bestehende Datei laden oder
    eine neue Instanz erstellen.
    Dann würde ich alles darauf loslassen, anstatt per Copy'n'Paste den Code doppelt reinzuklatschen. Diese "Programmiermethode" sorgt meines Erachtens
    für schlecht lesbaren und vor allem schlecht wartbaren Code (alle Änderungen müssen doppelt eingepflegt werden). Wenn meine obige Vermutung stimmt,
    wäre das schon der Beweis 😉

    Gruß,

    Alexander



  • ....shame on me 🙄

    Hallo!

    Danke für die Antwort und natürlich hast du recht.

    Es lag an der einen Zeile, die du zitiert hattest.
    Und natürlich mache ich mich mal ans Aufräumen des Codes.

    Einen schönen Tag noch!



  • So, die Zusammenlegung ist soweit abgeschlossen.

    Jedoch bekomme ich jetzt immer eine Exception bei der Ausführung, wenn die XML-Datei schon vorhanden ist:

    _di_IXMLNode tempKnoten1,tempKnoten2;
    
    TXMLDocument *XMLDocument=new TXMLDocument(""); // WICHTIG: kein Datei Namen übergeben, sonst Exception
    
      XMLDocument->FileName=FileName.c_str();
      XMLDocument->Options = XMLDocument->Options << doNodeAutoIndent;  // für die richtige Formatierung
      XMLDocument->LoadFromFile();
      XMLDocument->Active = true;
      if(XMLDocument->IsEmptyDoc()) // Gibt es die XML - Datei schon? 
      { // nein, dann neu erstellen
      XMLDocument->Encoding = "UTF-16";    // Encoding festlegen, damit auch z.B. Umlauten richtig rüberkommen
      tempKnoten1 = XMLDocument->CreateElement((tempNoteInfo =GetXMLNote(XMLString,1)).Node.c_str(), "");
      XMLDocument->DocumentElement = tempKnoten1;
      }
      else // Ja, dann den root - Knoten erhalten 
      tempKnoten1 = XMLDocument->DocumentElement; // <-- Hier die Exception
    

    Er kann irgendwie nicht den root-Knoten "XMLDocument->DocumentElement" erhalten.
    Jedoch ist die XML - Datei fehlerfrei, denn Aktive ist auch auf "true" und "IsEmptyDoc" auch false.

    Weiß jemand weiter?

    Hier zum nachvollziehen der Inhalt der XML-Datei

    <?xml version="1.0" encoding="UTF-16"?>
    <PROFILES>
      <TEST>
        <Wizzard>
          <Step1>Test1</Step1>
        </Wizzard>
      </TEST>
    </PROFILES>
    

Anmelden zum Antworten