Logikproblem Tinyxml



  • Hey, und zwar möchte ich via Tinyxml ein ganz bestimmtes Element auslesen aus einem XML String.

    Aufbau des Strings wäre Beispielsweise:

    <root>
       <child>
          <subchild>
             <first>Inhalt</first>   // Bis hierhin komm ich über eine Schleife
             <second>Inhalt</second>
             <third>Inhalt</third>   // Dieses Element will ich auslesen
             <fourth>Inhalt</fourth>
             <fifth>Inhalt</fifth>
          </subchild>
       <child>
    <root>
    

    Mein Code sieht momentan so aus:

    CString servicezugriff::getresult(CString xmlstring, CString searchnode)
    {
    	TiXmlDocument xmldoc;
    	xmldoc.Parse(xmlstring);
    	TiXmlNode *xmlnode = xmldoc.RootElement();
    	CString Values;
    	while(xmlnode != 0)
    	{
    		Values = Values +"\t"+xmlnode->Value(); // Um zu prüfen bis wohin die Schleife läuft
    		xmlnode = xmlnode->FirstChildElement();
    	}
    
    	return Values; // Hier soll am Ende das gesuchte Element zurück gegeben werden
    }
    

    Bitte nicht von CString ablenken lassen, ich ist zwar MFC aber der Rest nicht.

    Aus der Dokumentation zu Tinyxml werde ich in der Richtung nicht schlau. Ich hoffe, ihr könnt mir einen Denkanstoß geben wie ich an das gesuchte Element komme.

    // Lach ich bring mich hier selbst durcheinander mit den Codeformatierungen.



  • TinyXML ist kacke und hat Bugs.
    Schreib dir selbst nen Parser, das kann jeder besser.



  • Ich möcht hier nun nicht über Vor und Nachteile von Tinyxml duskutieren.

    Einen eigenen Parser zu schreiben würde das Problem zwar sicherlich beheben, aber in einem Zeitaufwand der ziemlich hoch wäre und das Rad muss nicht unbedingt neu erfunden werden. 😉

    Aus der Dokumentation von Tinyxml geht für mich hervor, dass mit der Methode NextSiblingElement() auf die Geschwisterelemente zugegriffen werden kann, also in diesem Fall second, third und so weiter.

    Aber wie prüfe ich ob das momentane Element das gesuchte ist?

    Probiert habe ich es über:

    if(xmlnode->Value()==xmlnode)
    

    Da erhalte ich aber eine Zugriffsverletzung.



  • Vll hilft dir das hier:

    const TiXmlElement* GetAttribute(const std::string &propertyName, const TiXmlElement* begin)
    {
    	for(; begin; begin = begin->NextSiblingElement())
    	{
    		const char *val = begin->Attribute("Name");
    		if(!strcmp(propertyName.c_str(), val))
    			return begin;
    	}
    
    	return nullptr;
    }
    

    bb


  • Administrator

    TiXmlDocument xmldoc;
    xmldoc.Parse(xmlstring);
    
    TiXmlHandle handle(&xmldoc);
    
    handle.FirstChild("root");
    handle.FirstChild("child");
    handle.FirstChild("subchild");
    handle.FirstChild("thrid");
    
    TiXmlElement* elem = handle.ToElement();
    
    if(elem)
    {
      // vorhanden ...
    }
    

    Einfach so aus dem Kopf heraus. Keine Garantie auf Korrektheit. Aber ist ja wirklich nicht so schwer. Lies doch einfach mal die Dokumentation.

    Hier hast du fast ein 1:1 Beispiel von deinem Fall:
    http://www.grinninglizard.com/tinyxmldocs/classTiXmlHandle.html

    Grüssli



  • Dravere schrieb:

    TiXmlDocument xmldoc;
    xmldoc.Parse(xmlstring);
    
    TiXmlHandle handle(&xmldoc);
    
    handle.FirstChild("root");
    handle.FirstChild("child");
    handle.FirstChild("subchild");
    handle.FirstChild("thrid");
    
    TiXmlElement* elem = handle.ToElement();
    
    if(elem)
    {
      // vorhanden ...
    }
    

    Einfach so aus dem Kopf heraus. Keine Garantie auf Korrektheit. Aber ist ja wirklich nicht so schwer. Lies doch einfach mal die Dokumentation.

    Hier hast du fast ein 1:1 Beispiel von deinem Fall:
    http://www.grinninglizard.com/tinyxmldocs/classTiXmlHandle.html

    Grüssli

    Naja soweit ok, da weis ich dass das Element existiert aber das wusst ich vorher schon. 🙂

    Es ist so, dass ich eine Antwort eines Webservice erhalte und mit Tinyxml eben die wichtigen Knoten abfragen will über die von mir geschriebene Funktion.
    So, da die Funktion allgemeingültig sein soll funktioniert es so nicht.

    Auf deine Weise kann ich nur auf das eine Element zugreifen. Rufe ich die Funktion nocheinmal auf, kommt das selbe Resultat.

    Wäre aber unvorteilhaft bei verschiedenen XML Dateien, die ich mit der Funktion dann auswerten möchte.

    // unskilled deins sieht aus, als könnte es funktionieren. Werd ich direkt mal testen.


  • Administrator

    inflames2k schrieb:

    Es ist so, dass ich eine Antwort eines Webservice erhalte und mit Tinyxml eben die wichtigen Knoten abfragen will über die von mir geschriebene Funktion.
    So, da die Funktion allgemeingültig sein soll funktioniert es so nicht.

    Auf deine Weise kann ich nur auf das eine Element zugreifen. Rufe ich die Funktion nocheinmal auf, kommt das selbe Resultat.

    Häää?
    Denk doch bitte mal ein bisschen mit! Du kannst die festen Stringliterale auch durch variablen ersetzen! Statt "third" kannst du dort auch dein CString Objekt übergeben, du musst es nur in einen std::string oder char const* konvertieren.

    Die Prüfung ob es vorhanden ist, ist einfach zur Sicherheit dort. Du hast aber dann ein TiXmlElement Objekt, welches dir auch entsprechenden Zugriff auf den Knoten gibt.

    Grüssli



  • Hab noch eine Frage, für mich zum Verständniss.
    Und zwar FirstChildElement(wert), ich habe es so verstanden, dass er hier das erste Element welches den Tagnamen wert hat nimmt. Versteh ich das Falsch?
    Wenn ja, kann mir einer kurz erklären, was er da auswählt?



  • inflames2k schrieb:

    Hab noch eine Frage, für mich zum Verständniss.
    Und zwar FirstChildElement(wert), ich habe es so verstanden, dass er hier das erste Element welches den Tagnamen wert hat nimmt. Versteh ich das Falsch?
    Wenn ja, kann mir einer kurz erklären, was er da auswählt?

    ein element ist zu mindest in der Qt4-Implementierung so was

    <element />
    

    Da die sich an den DOM-Standard halten wird das auch bei TinyXml zutreffen.
    Und ein firstChildElement("test") gibt das erste Element <test /> zurück.
    Diese DomNode hat dann einen nodeName() == "test".
    Wenn du aber nicht nur das erste ChildElement mit dem nodeName haben willst, musst du von dem ersten Fund mit nextSiblingElement() weiter machen.



  • Ok, also hab ich das doch richtig verstanden. 🙂
    Danke.

    // Achja bevor ichs vergesse, ich hab nun erreicht was ich wollte.

    Falls jemand mal eine ähnliche Funktion braucht hier der Quelltest:

    CString getresult(CString xmlstring, CString searchnode)
    {
    	TiXmlDocument xmldoc;
    	xmldoc.Parse(xmlstring);
    
    	TiXmlNode *xmlnode = xmldoc.RootElement();
    	CString Value;
    
    	// Den XML-String durchgehen, bis ein Element kommt ohne Child
    	int i=0;
    	do
    	{		
    		xmlnode = xmlnode->FirstChildElement();	
    		i++;	
    	}while(xmlnode != 0);
    
    	TiXmlNode *xmlnode2 = xmldoc.RootElement();
    
             // Bis zum letzten Element mit Childs durchgehen
    	for(int j=0; j<i-1; j++)
    	{		
    		xmlnode2 = xmlnode2->FirstChildElement();
    	}
    
    	TiXmlElement *elem = xmlnode2->ToElement();
    
             // Das Childelement mit dem gesuchten Namen aufrufen
    	elem = elem->NextSiblingElement((LPCTSTR)searchnode);
    
             if(elem)
    		Value = elem->GetText();
             // Else Teil hier nur für meine bedürfnisse, da ich den 1. Child brauche
    	else
    	{
    		xmlnode2 = xmlnode2->IterateChildren(xmlnode);
    		Value = Value+xmlnode2->Value();
    	}
    	return Value;
    }
    

Anmelden zum Antworten