Einfacher XML-Parser



  • Hi
    Welchen einfachen XML-Parser könnt ihr mir empfehlen. Für mein Projekt muss ich Daten aus einer XML-Datei die als Config-Datei dient auslesen.
    Wichtig ist, dass er wirklich einfach zu verwenden ist und auch einfach einzubinden.
    Hab schon mal ein bißchen gesucht und Parser wie TinyXML RapidXML und Xerces gefunden.
    Wie ist das denn mit der Geschwindigkeit. Habe gelesen dass RapidXML einiges schneller ist als die anderen. Kann nur aber leider überhaupt nicht abschätzen in welchen Größenordnungen sich das bewegt.
    Also wenn das File ein mal eingelesen wurde sollten die eigentlichen "Suchaktionen" nach bestimmten Paramtern nicht länger als 5ms dauern. Ist das mit den oben aufgelisteten parsern zu schaffen (die größe des XML-Files wird überschaubar sein)

    Danke schonmal
    Gruß Zaus



  • Geschwindigkeit ist erst ab mehreren Mega- oder gar Gigabytes an Eingaben ein Thema. TinyXML hab ich mal verwendet und war zufrieden.



  • Kann nichtmal ne Datei öffnen...
    Die 4 cpp und 2 Header-Dateien sind eingebunden...

    #include "tinystr.h"
    #include "tinyxml.h"
    
    void xml_test()
    {
    
    	TiXmlDocument doc("D:\\testxml.xml");
    	doc.LoadFile();
    }
    

    Gibt einige Warnungen und Fehlermeldungen :
    Warnung 1 warning C4627: "#include "tinystr.h"": Wird bei der Suche nach Verwendung des vorkompilierten Headers übersprungen.

    Fehler 2 fatal error C1010: Unerwartetes Dateiende während der Suche nach dem vorkompilierten Header. Haben Sie möglicherweise vergessen, im Quellcode "#include "stdafx.h"" einzufügen?

    alle Fehler und Warnungen sehen derart aus.



  • Erstell ein Projekt ohne vorkompilierte Header oder folge den Anweisungen:

    Haben Sie möglicherweise vergessen, im Quellcode "#include "stdafx.h"" einzufügen?



  • Zaus schrieb:

    Also wenn das File ein mal eingelesen wurde sollten die eigentlichen "Suchaktionen" nach bestimmten Paramtern nicht länger als 5ms dauern.

    Wer macht den diese Vorgabe?

    Zaus schrieb:

    Haben Sie möglicherweise vergessen, im Quellcode "#include "stdafx.h"" einzufügen?

    😃 👍



  • Natürlich ist stdafx.h eingefügt 🙂
    Die Vorgabe mit den 5 ms mache ich. Das Programm erzeugt später Steuerbefehle bei denen es wichtig ist, dass es keine Verzögerungen gibt.

    Kann ich das mit dem vorkompilierten Header bei Visual Studio 2008 noch nachträglich ändern oder muss ich n neues Projekt machen?
    Hab ich irgendwelche nachteile dadurch wenn ich das ohne vorkompilierten Header mache?


  • Administrator

    Blue-Tiger schrieb:

    Geschwindigkeit ist erst ab mehreren Mega- oder gar Gigabytes an Eingaben ein Thema. TinyXML hab ich mal verwendet und war zufrieden.

    Naja. Ich habe es für ein 700 Kilobyte verwendet. Da hat TinyXML auf gewissen Computern bis zu einer Sekunde dafür benötigt. RapidXML habe ich in letzter Zeit ein wenig angetestet und war hochzufrieden damit. Das File wurde innert weniger Millisekunden eingelesen.
    In der Zugriffszeit werden sich TinyXML und RapidXML wahrscheinlich nicht stark unterscheiden.

    Ich persönlich würde zu RapidXML raten. Ist modernes C++ und hat einen wirklich sehr schnellen Parser. Zudem ist RapidXML eine Header-Only Bibliothek. Wirklich sehr einfach einzubinden.
    Der einzige Kritikpunkt an RapidXML ist, den ich finden konnte, dass es keinen XML Iterator hat. Das Iterieren über die Nodes ist ein wenig mühsam. Allerdings kann man sich auf die Schnelle einen eigenen Iterator basteln. Zum Beispiel so:

    template<typename CharT = char>
    class xml_iterator
    	: public boost::bidirectional_iterator_helper
    		<xml_iterator<CharT>, xml_node<CharT>* >
    {
    private:
    	xml_node<CharT>* m_parent;
    	xml_node<CharT>* m_node;
    	char const* m_name;
    	std::size_t m_name_size;
    	bool m_case_sensitiv;
    
    public:
    	xml_iterator()
    		: m_parent(0)
    		, m_node(0)
    		, m_name(0)
    		, m_name_size(0)
    		, m_case_sensitiv(true)
    	{
    	}
    
    	xml_iterator(
    		xml_node<CharT>& parent,
    		char const* name = 0,
    		std::size_t name_size = 0,
    		bool case_sensitiv = true)
    		: m_parent(&parent)
    		, m_node(parent.first_node(name, name_size, case_sensitiv))
    		, m_name_size(name_size)
    		, m_case_sensitiv(case_sensitiv)
    	{
    	}
    
    public:
    	xml_iterator operator ++()
    	{
    		if(m_node)
    		{
    			m_node = m_node->next_sibling(m_name, m_name_size, m_case_sensitiv);
    		}
    
    		return *this;
    	}
    
    	xml_iterator operator --()
    	{
    		if(m_node)
    		{
    			xml_node<CharT>* prev
    				= m_node->previous_sibling(m_name, m_name_size, m_case_sensitiv);
    
    			if(prev)
    			{
    				m_node = prev;
    			}
    		}
    		else if(m_parent)
    		{
    			m_node = m_parent->last_node(m_name, m_name_size, m_case_sensitiv);
    		}
    
    		return *this;
    	}
    
    	bool operator ==(xml_iterator iter) const
    	{
    		return m_node == iter.m_node;
    	}
    
    	xml_node<CharT>* operator ->() const
    	{
    		return m_node;
    	}
    };
    

    Sicher noch verbesserungswürdig... 🙂

    @Zaus,
    Ja, du kannst es in den Projekteigenschaften abstellen gehen.
    Project Properties -> Configuration Properties -> C/C++ -> Precompiled Headers

    Grüssli



  • Hm habs auf "Vorkompilierte Header nicht verwenden" gestellt ändert aber leider nichts. Was mach ich falsch?

    Nochmal zu der Geschwindigkeit: Sobald das File einmal eingelesen ist und nur noch darin gesucht wird unterscheiden sich die Geschwindigkeiten nicht mehr groß?
    Also die angesprochene Sekunde bezog sich auf das einlesen?

    Danke und Gruß
    Zaus


  • Administrator

    Zaus schrieb:

    Hm habs auf "Vorkompilierte Header nicht verwenden" gestellt ändert aber leider nichts. Was mach ich falsch?

    Immer noch die gleiche Fehlermeldung oder was heisst "ändert nichts"?

    Zaus schrieb:

    Nochmal zu der Geschwindigkeit: Sobald das File einmal eingelesen ist und nur noch darin gesucht wird unterscheiden sich die Geschwindigkeiten nicht mehr groß?
    Also die angesprochene Sekunde bezog sich auf das einlesen?

    Ja, die Sekunde bezog sich ausschliesslich auf das Einlesen. Der Zugriff dürfte in etwa gleich sein. Vielleicht könnte RapidXML etwas schneller sein, aber so minimal, dass es wahrscheinlich schwierig wäre, dies zu messen 🙂

    Grüssli



  • Ja genau immer noch dieselben Fehlermeldungen und Warnungen wie davor.


  • Administrator

    Zaus schrieb:

    Ja genau immer noch dieselben Fehlermeldungen und Warnungen wie davor.

    Bist du sicher, dass du es auch in beiden Konfigurationen (Release und Debug) abgestellt hast? Ansonsten Projekt neu erstellen oder zuoberst ein #include "stdafx.h" rein, sofern du bereits einen solchen Header hast.

    Grüssli



  • Ja es war in allen Konfigurationen abgestellt...
    Mit neuem Projekt funktioniert es jetzt, danke.



  • Dravere schrieb:

    Der einzige Kritikpunkt an RapidXML ist, den ich finden konnte, dass es keinen XML Iterator hat. Das Iterieren über die Nodes ist ein wenig mühsam. Allerdings kann man sich auf die Schnelle einen eigenen Iterator basteln.

    Gibt es doch oder?

    namespace rapidxml
    
    {
    
        //! Iterator of child nodes of xml_node
    
        template<class Ch>
    
        class node_iterator
    
        {
    
        public:
    
            typedef typename xml_node<Ch> value_type;
    
            typedef typename xml_node<Ch> &reference;
    
            typedef typename xml_node<Ch> *pointer;
    
            typedef std::ptrdiff_t difference_type;
    
            typedef std::bidirectional_iterator_tag iterator_category;
    
            node_iterator()
    
                : m_node(0)
    
            {
    
            }
    
            node_iterator(xml_node<Ch> *node)
    
                : m_node(node->first_node())
    
            {
    
            }
    
            reference operator *() const
    
            {
    
                assert(m_node);
    
                return *m_node;
    
            }
    
            pointer operator->() const
    
            {
    
                assert(m_node);
    
                return m_node;
    
            }
    
            node_iterator& operator++()
    
            {
    
                assert(m_node);
    
                m_node = m_node->next_sibling();
    
                return *this;
    
            }
    
            node_iterator operator++(int)
    
            {
    
                node_iterator tmp = *this;
    
                ++this;
    
                return tmp;
    
            }
    
            node_iterator& operator--()
    
            {
    
                assert(m_node && m_node->previous_sibling());
    
                m_node = m_node->previous_sibling();
    
                return *this;
    
            }
    
            node_iterator operator--(int)
    
            {
    
                node_iterator tmp = *this;
    
                ++this;
    
                return tmp;
    
            }
    
            bool operator ==(const node_iterator<Ch> &rhs)
    
            {
    
                return m_node == rhs.m_node;
    
            }
    
            bool operator !=(const node_iterator<Ch> &rhs)
    
            {
    
                return m_node != rhs.m_node;
    
            }
    
        private:
    
            xml_node<Ch> *m_node;
    
        };
    
        //! Iterator of child attributes of xml_node
    
        template<class Ch>
    
        class attribute_iterator
    
        {
    
        public:
    
            typedef typename xml_attribute<Ch> value_type;
    
            typedef typename xml_attribute<Ch> &reference;
    
            typedef typename xml_attribute<Ch> *pointer;
    
            typedef std::ptrdiff_t difference_type;
    
            typedef std::bidirectional_iterator_tag iterator_category;
    
            attribute_iterator()
    
                : m_attribute(0)
    
            {
    
            }
    
            attribute_iterator(xml_node<Ch> *node)
    
                : m_attribute(node->first_attribute())
    
            {
    
            }
    
            reference operator *() const
    
            {
    
                assert(m_attribute);
    
                return *m_attribute;
    
            }
    
            pointer operator->() const
    
            {
    
                assert(m_attribute);
    
                return m_attribute;
    
            }
    
            attribute_iterator& operator++()
    
            {
    
                assert(m_attribute);
    
                m_attribute = m_attribute->next_attribute();
    
                return *this;
    
            }
    
            attribute_iterator operator++(int)
    
            {
    
                attribute_iterator tmp = *this;
    
                ++this;
    
                return tmp;
    
            }
    
            attribute_iterator& operator--()
    
            {
    
                assert(m_attribute && m_attribute->previous_attribute());
    
                m_attribute = m_attribute->previous_attribute();
    
                return *this;
    
            }
    
            attribute_iterator operator--(int)
    
            {
    
                attribute_iterator tmp = *this;
    
                ++this;
    
                return tmp;
    
            }
    
            bool operator ==(const attribute_iterator<Ch> &rhs)
    
            {
    
                return m_attribute == rhs.m_attribute;
    
            }
    
            bool operator !=(const attribute_iterator<Ch> &rhs)
    
            {
    
                return m_attribute != rhs.m_attribute;
    
            }
    
        private:
    
            xml_attribute<Ch> *m_attribute;
    
        };
    
    }
    

  • Administrator

    hasehasehase schrieb:

    Dravere schrieb:

    Der einzige Kritikpunkt an RapidXML ist, den ich finden konnte, dass es keinen XML Iterator hat. Das Iterieren über die Nodes ist ein wenig mühsam. Allerdings kann man sich auf die Schnelle einen eigenen Iterator basteln.

    Gibt es doch oder?

    Keine Ahnung woher du den hast. Ich konnte jedenfalls in der Dokumentation nichts dazu finden und was nicht dokumentiert ist, verwende ich normalerweise auch nicht.

    Grüssli



  • Dravere schrieb:

    Keine Ahnung woher du den hast.

    Download -> 4 Dateien. 🙂



  • Boost.PropertyTree ist ganz gut. Das verwendet intern RapidXML.
    http://www.boost.org/doc/libs/1_43_0/doc/html/property_tree.html



  • hasehasehase schrieb:

    Dravere schrieb:

    Keine Ahnung woher du den hast.

    Download -> 4 Dateien. 🙂

    Du solltest auch ausprobieren, was du da empfiehlst! Der iterators-code ist noch total verbuggt, kompiliert nicht! Z.B.

    node_iterator operator++(int)
            {
                node_iterator tmp = *this;
                ++this;
                return tmp;
            }
    

    ++this geht nicht, da this ein const pointer ist.
    Steht aber auch irgendwo in der Doku, dass die iterators noch nicht fertig sind.
    Wäre schön, wenn es dann auch irgendwo ein xml_node::end() gäbe, damit man auch dagegen prüfen könnte.



  • Ich hol den Thread nochmal hoch weil ich noch eine Frage habe.
    Hab bis jetzt mit TinyXML gearbeitet würde jetzt aber zum Vergleich auch gerne rapidxml ausprobieren.
    Ich schaffe es aber nicht einen Integer-Wert aus einem Attribut auszulesen.
    Bei TinyXML ging das zB mit QueryIntAttribute, bei rapidxml konnte ich aber nichts entsprechendes finden.

    Gruß Zaus



  • Schau dir doch die TinyXML-Sourcen an wie das da gemacht wird 😉
    XML kennt eigentlich nur Strings, deshalb gibt RapidMLX auch strings zurück. Wenn da ein anderer Wert drinnen steckt, muss das gecastet werden. boost::lexical_cast oder die Variante über std::stringstream gehen da genauso wie sscanf. Letzteres nimmt TinyXML. Wobei man streiten kann, ob die Konvertierung als Klassenmethode wirklich notwendig ist, denn im Prinzip kannst du den Aufruf sehr gut selber machen, ohne mehr Code schreiben zu müssen:

    int value;
    sscanf(rapixml_node.value(), "%d", &value);
    

    sollte gehen. sscanf hat natürlich auch einen return, den man abfangen kann 🙂



  • Danke 🙂

    Habe noch ne andere Frage und hoffe mal du kannst sie mir beantworten dann erspar ich den andereren nen extra Thread dazu.
    Beim ausführen des Programms bekomme ich folgende Nachricht im "Direktfenster" von VS:

    Eine Ausnahme (erste Chance) bei 0x7723b727 in MIDIrapid.exe: 0x000006BA: The RPC server is unavailable.

    Bei der TinyXML-Version erscheint dabei 3 mal diese Fehlermeldung, bei der rapidxml 4 mal. Wenn ich Debugge und den ersten Break-Point direkt zu anfang setze kommen diese Meldungen trotzdem. Das Programm läuft aber ganz normal und funktioniert auch...
    Konnte leider mit Google nicht rausfinden was das genau bedeutet und wie ich es beheben kann.

    Gruß Zaus


Log in to reply