[Xerces] DOM-Verarbeitung in mehreren Funktionen



  • Hallo!

    Ich benutze die Xerces c++ Bibliothek und stehe gerade vor einem Programmierproblem. Ich verarbeite per DOM in einer Funktion einen XML-String. Dazu benutze ich den XercesDOMParser. Nun würde ich gerne das DOMDocument zurückgeben und es in einer anderen Funktion in einer anderen Klasse weiterverarbeiten. Wenn ich dies mache bekomme ich jede Menge Speicherlecks, weil ich zwar den Zeiger auf das DOMDocument löschen kann, nicht aber den Parser. Wenn ich diesen nämlich vorher lösche ist auch mein DOMDocument futsch. Deswegen frage ich mich, ob das überhaupt der richtige Weg ist um ein Dokument anderen Funktionen zur Weiterverarbeitung zur Verfügung zu stellen.

    XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* CXMLTest::parseMyString2()
    {
    	XercesDOMParser* parser = new XercesDOMParser();
    	parser->setValidationScheme(XercesDOMParser::Val_Always); // optional.
    	parser->setDoNamespaces(true); // optional
    	char* xmlStream = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><FUNCTION NAME=\"GET_MEASURESTATUS\" ID=\"1149758883\" KENNUNG=\"dd1\" PWD=\"dd1\"/>";
    	static const char* pstrMemBufId = "myTest"; 
    
    	MemBufInputSource* memBufIS = new MemBufInputSource
    	(
    		( const XMLByte* )xmlStream
    		, strlen( xmlStream )
    		, pstrMemBufId
    		, false
    	);
    
    	try 
    	{
    		parser->parse( *memBufIS );
    	}
    	catch (...) 
    	{
    		delete memBufIS;
    
    		return false;
    	}
    	return parser->getDocument();
    }
    

    Wie geht man denn in diesem Fall vor?

    Gruß

    Sascha



  • Du mußt das Dokument natürlich sichern, bevor du den dazugehörigen Parser freigeben willst:

    DomDocument* dok = parser->GetDocument()
    delete parser;
    return dok;
    

    Alternativ könntest du den Parser auch aktiv halten, solange dein CXMLTest-Objekt existiert (als Membervariable, die erst im Dtor freigegeben wird).



  • Vielen Dank für die rasche Antwort. Leider werden aber beim Freigeben des Parsers auch alle darin enthaltenen Dokumente gelöscht. Ein Zugriff auf das DOMDocument ist nach dem Löschen des Parsers nicht mehr möglich.



  • wenn du den parser loeschen willst, musst du die XML daten halt vorher in deine eigene struktur ueberfuehren.
    Stell dir dom einfach als riesigen uneffektiven cache vor, denn du bei bedarf einfach "serialisieren" willst kannst darfst.

    Deshalb macht DOM vor allem in solchen szenarien Sinn, wo du nen geparstes XML file im Speicher (DOM Dokument hasst) der als cache fuer die einstellungen fuer nen anderes Lebendes Objekt dient.
    Z.b. Ne Aplication wo deine Fenster sich serialisieren ... die fenster selber bekommen nen verweis auf ihren DOM Node, und schreiben /lesen da drinne.
    Am anfang wird das XML dokument geparst, und wenn App zu ende, wird der inhalt weggeschrieben und der parser zerstoert.

    Auch wenn das ned hoeren willst,
    fuer alle komplizierteren Dinge ist rein performancetechnisch und so weiter ist SAX einfach die bessere wahl.

    Ciao ...



  • Hallo RHBaum!
    Vielen Dank für die Antwort. Leider helfen mir Deine Ausführungen jetzt auch nicht. Ich habe ein Programm bei dem ich den vorhandenen Parser durch Xerces ersetze. Also steht das Design der Anwendung auch schon fest.

    Es ist einfach so, dass ich in einer Klasse das XML-Dokument parse und zur weiteren Verarbeitung einer anderen Klasse übergeben muss.

    Deswegen hätte ich gern gewusst, wie hier der klassische Weg aussieht. Leider gibt die Dokumentation zu Xerces dazu und zu vielen anderen Dingen nicht viel her. Es gibt eine Menge Objekte, aber nur unzureichend erklärt und ohne Beispiele.



  • anstatt DOMDocument direkt zu verwenden, versuch mal mit dem Proxy Object. etwa so:

    class DomDocumentProxy
    {
      public:
        DomDocumentProxy(XercesDOMParser *);
        DomDocumentProxy(const DomDocumentProxy &);
    
        DOMDocument *getDocument();
    
      private:
        boost::shared_ptr<XercesDOMParser> parser;
    };
    


  • Hallo ssm!

    Vielen Dank für Deinen Beitrag! Wäre nett, wenn Du mir Deinen Codeschnippsel erklären könntest.



  • Was ssm dir in c++ worten sagen will : ^^

    dein parser muss solangegueltig (also nicht geloescht) sein, solange du zugriff auf dein Document brauchst ^^

    wie man die lebensdauer eines objects gestaltet, kann sehr unterschiedlich sein. smartpointer sind ne sehr elegante loesung in bestimmten anwandungsfaellen ...

    Das sind aber tiefste c++ grundlagen ....

    Ciao ...



  • Sascha Bahl schrieb:

    Wäre nett, wenn Du mir Deinen Codeschnippsel erklären könntest.

    Eigentlich hat RHBaum alles gesagt, was ich sagen wollte 👍
    Noch ein Codesnippet shadet denke ich nicht 🙂

    typedef boost::shared_ptr<XercesDOMParser>  XercesDOMParserPtr; 
    
    class DomDocumentProxy 
    { 
      public: 
        explicit DomDocumentProxy(const DomDocumentProxy &obj)
    	:	parser(obj.parser)
        {
        }
    
        explicit DomDocumentProxy(XercesDOMParserPtr parser)
    	:	parser(parser)
        {
        }
    
        DOMDocument *getDocument()
        {
            return parser->getDocument();
        }
    
      private: 
        XercesDOMParserPtr parser; 
    }; 
    
    DomDocumentProxy CXMLTest::parseMyString2() 
    { 
        XercesDOMParserPtr parser(new XercesDOMParser()); 
        parser->setValidationScheme(XercesDOMParser::Val_Always); // optional. 
        parser->setDoNamespaces(true); // optional 
        char* xmlStream = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><FUNCTION NAME=\"GET_MEASURESTATUS\" ID=\"1149758883\" KENNUNG=\"dd1\" PWD=\"dd1\"/>"; 
        static const char* pstrMemBufId = "myTest"; 
    
        std::auto_ptr<MemBufInputSource> memBufIS(new MemBufInputSource 
            ( const XMLByte* )xmlStream, strlen( xmlStream ), pstrMemBufId, false));
    
        parser->parse(*memBufIS); 
    
        return DomDocumentProxy(parser);
    }
    

    so würdest du dann die Methode vervenden:

    {
       DomDocumentProxy myDocProxy = parseMyString2();
       DOMDocument myDoc = myDocProxy->getDocument();
    
       myDoc->appendChild(
    	myDoc->createElement("aaa"));
       {
           DomDocumentProxy proxy2 = myDocProxy;
           ....
       }   
    }
    

    XercesDOMParserPtr sorgt dafür, dass Objekt des Klasses XercesDOMParser nur dann zerstört wird, wenn auf ihn keine References gibt.

    P.S. hoffe du kannst mein Deutsch verstehen :-)))

    edit : "explicit" shadet auch nicht 🙂



  • Ja, super! Danke, ssm! Ich war mir über diese Methoden gar nicht so bewusst. Nun habe ich mir auch boost installiert. Werde ich wohl jetzt öfter verwenden. Ach, RHBaum: Grundlagen würde ich das jetzt nicht nennen, aber der Mensch ist ja lernfähig 😉

    Ich habe allerdings das Beispiel etwas modifizieren müssen. Aus der Klasse DomDocumentProxy habe ich die explicit entfernt. Bei der Verwendung der Methode würde es dann eher so heissen:

    DomDocumentProxy myDocProxy = xml_test.parseMyString2();
    XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* myDoc = myDocProxy.getDocument();
    

    myDoc muss ein Pointer auf DOMDocument sein. Methoden der Proxy-Klasse werden über den Punkt-Operator angesprochen.

    Aber jetzt funktioniert das wirklich super und mein Problem ist damit gelöst. Vielen Dank an alle.



  • Ach, RHBaum: Grundlagen würde ich das jetzt nicht nennen, aber der Mensch ist ja lernfähig 😉

    Ich denk schon das betrachtungen zur lebensdauer von Objekten zu den Grundlagen gehoeren ... und das man gewisse Techniken um die Lebensdauer zu beeinflussen kennen sollte.
    Ok, bei mir gehoert zu den Grundlagen halt nich nur, das man jedes c++ schluesselwort herbeten kann, sondern auch gewisse techniken und methoden.

    Ob nen proxy an der stelle mittels smartpointer ueberhaupt notwendig ist, da mag ich meine Hand ned ins Feuer legen fuer. Denk mal ne einfache verschiebung der parserinstanz an ne langlebigere stelle haette es auch getan.

    Aber schadet auf der anderen seite auch nicht, und der performance und speicheroverhead wird Dir an der stelle nicht wirklich was ausmachen. Dafuer bekommst ne weitere Abstraktion, und du lernst noch was dazu ^^

    Ciao ...


Anmelden zum Antworten