Immernoch Probleme mit TinyXML



  • Hallo,

    ich habe mehrere Einträge in meiner XML Datei in der Form:

    <root>
        <Icon Name="1.txt" X="-2.35" Y="1.56" Z="-5.5" />
        <Icon Name="1717_arbeitsdateien" X="-2.35" Y="1.26" Z="-5.5" />
    ...
    </root>
    

    Eine Methode soll jetzt über alle Elemente iterieren, falls ein Element mit dem übergebenen Namen übereinstimmt sollen die X,Y,Z Werte aktualisiert werden.

    Die Methode:

    BOOL updateElement(TiXmlElement element)
    {
    
    	// Get the config file
    	TiXmlDocument doc( (char*)positionDataFile.c_str() );
    
    	// Try loading config file
    	if ( !doc.LoadFile() )	
    		cout << "could not read file";
    
    	BOOL result = false;
    
    	TiXmlNode * iNode = doc.FirstChild( "root" );
    	TiXmlNode * itemNode = iNode->FirstChild( "Icon" );
    
    	if( iNode != NULL )
    	{
    		while( itemNode != NULL )
    		{
    
    			string temp1 = itemNode->ToElement()->Attribute("Name");
    			string temp2 = element.ToElement()->Attribute("Name");
    
    			if(strcmp(temp1.c_str(), temp2.c_str()) == 0)
    			{
    				itemNode->ToElement()->SetAttribute("X", element.ToElement()->Attribute("X"));
    				itemNode->ToElement()->SetAttribute("Y", element.ToElement()->Attribute("Y"));
    				itemNode->ToElement()->SetAttribute("Z", element.ToElement()->Attribute("Z"));
    
    				cout << "Setting Z of element: " << temp2 << "to: " << element.ToElement()->Attribute("Z") << "\n";
    
    				result = true;
    				break;
    			}
    
    			itemNode = iNode->IterateChildren( "Icon", itemNode );
    		}
    	}
    
    	doc.SaveFile();
    	return result;
    }
    

    Der Aufruf:

    // Set attributes for an Element. 
    	wert.SetAttribute("Name", name);
    	wert.SetAttribute("X", xString.c_str());
    	wert.SetAttribute("Y", yString.c_str());
    	wert.SetAttribute("Z", zString.c_str());
    
    	// Get the root Element 
    	root = doc.FirstChildElement("root");
    	if (root)
    	{
    
    		// This checks if the node wert is already in the .xml file
    		// If it is inside, the values will be updated.
    		if(!updateElement(wert))
    			root->InsertEndChild(wert);
    }
    

    Das Problem: das Aktualisieren klappt nicht. Dh die updateElement Methode hat wohl noch einen Bug, den ich aber nicht finde. Hat jemand eine Idee?

    Gruß
    Alex



  • if(strcmp(temp1.c_str(), temp2.c_str()) == 0)
    

    Wieso nicht einfach

    if(temp1 == temp2)
    

    ?


  • Administrator

    filth schrieb:

    Das Problem: das Aktualisieren klappt nicht. Dh die updateElement Methode hat wohl noch einen Bug, den ich aber nicht finde. Hat jemand eine Idee?

    Tausende ...

    Aber zuerst einmal:

    TiXmlDocument doc( (char*)positionDataFile.c_str() );
    

    Was hatte ich gesagt? Böse! Aus! :p

    Zu deinem Problem:
    Hast du schon mal mit C++ gearbeitet und/oder mal die TinyXML Dokumentation durchgelesen? Dein Vorgehen ist zum Scheitern verdammt 🙂

    Ich stelle wohl am einfachsten ein paar Fragen:
    - Wieso öffnest du in der Funktion das Dokument erneut und speicherst es am Ende wieder? Wieso übergibst du nicht das Dokument, welches du bereits geöffnet hast per Referenz? Da wird am Ende sicher das falsche Dokument gespeichert.
    - Wieso verwendest du BOOL , statt bool ? Zu viel Windowsprogrammierung gehabt?
    - Wieso übergibst du ein TiXmlElement Objekt und nimmst es intern dann wieder auseinander. Wieso nicht gleich die Parameter übergeben, am besten per const-Referenz?
    - Wieso vergleichst du die std::string nicht direkt miteinander, sondern mühsam über C-Funktionen?
    - Wieso iterierst du so kompliziert durch deine Nodes und zum Beispiel nicht gleich über die Elemente und ihren Geschwistern?
    - Wieso fügst du das Element nicht gleich in der Funktion ein? Dann kannst du dir den Rückgabewert ersparen!
    - Wieso verwendest du eine BOOL result Variable? Wieso da mal wieder BOOL statt bool und wieso nicht in der Funktion statt des break lieber gleich ein return true ?
    - Rufst du diese updateElement Funktion mehrmals hintereinander auf? Dann wäre das noch extrem ineffizient!

    Das wäre es soweit einmal von mir. Mehr fällt mir jetzt grad nicht ein an Fragen. Ich persönlich würde alles in deinem Code umschreiben 😉

    Grüssli



  • Hi,

    danke für die Tipps. Nun funktioniert es.

    Habe es so gelöst:

    bool updateElement(TiXmlElement element, TiXmlDocument &doc)
    {
    
    	bool result = false;
    
    	TiXmlNode * iNode = doc.FirstChild( "root" );
    	TiXmlNode * itemNode = iNode->FirstChild( "Icon" );
    
    	if( iNode != NULL )
    	{
    		while( itemNode != NULL )
    		{
    
    			string temp1 = itemNode->ToElement()->Attribute("Name");
    			string temp2 = element.ToElement()->Attribute("Name");
    
    			// If the names are equal set the values to the passed values
    			if(strcmp(temp1.c_str(), temp2.c_str()) == 0)
    			{
    
    				itemNode->ToElement()->SetAttribute("X", element.ToElement()->Attribute("X"));
    				itemNode->ToElement()->SetAttribute("Y", element.ToElement()->Attribute("Y"));
    				itemNode->ToElement()->SetAttribute("Z", element.ToElement()->Attribute("Z"));
    
    				result = true;
    			}
    
    			itemNode = iNode->IterateChildren( "Icon", itemNode );
    		}
    	}
    
    	return result;
    }
    

  • Administrator

    Du hast sicher nochmals die Hälfe der Tipps ausgelassen, deshalb konnte ich jetzt nicht anders ...

    bool updateElement(TiXmlDocument& doc,
                       std::string const& name,
                       std::string const& valueX,
                       std::string const& valueY,
                       std::string const& valueZ)
    {
      TiXmlElement* element = doc.FirstChildElement("root");
    
      if(element)
      { element = element->FirstChildElement("Icon"); }
    
      char const* attrName;
    
      while(0 != element) 
      {
        attrName = element->Attribute("Name");
    
        // If the names are equal set the values to the passed values 
        if(attrName != 0 && name == attrName) 
        {
          element->SetAttribute("X", valueX);
          element->SetAttribute("Y", valueY);
          element->SetAttribute("Z", valueZ);
    
          return true;
        }
    
        element = element->NextSiblingElement("Icon");
      }
    
      return false;
    }
    

    Grüssli



  • Naa gut, Danke! 🙂


Anmelden zum Antworten