Seite 1 von 1

Navigation durch xml Dokumente

Verfasst: 8. Dezember 2010 00:41
von surfhai
Hallo,

ich weiß es kann trivial klingen, aber ich komm einfach nicht klar. Ich hab ein xml Dokument aus einer OpenOffice Spreadsheet Datei (content.xml) aus dem ich Werte auslesen will.

Da dacht ich mir les ich es mit einem QDomDocument ein. Hab mich hier http://zez.org/article/articleview/28/1/ etwas über die Struktur informiert aber blick nicht ganz durch wie ich das ganze Durchlaufen soll.

hier mal meine ersten versuche damit klar zu kommen:

Code: Alles auswählen

QDomDocument
Utils::readODS(QString filepath)
{
    QuaZipFile zipfile;
    zipfile.setZipName(filepath);
    zipfile.setFileName(QString("content.xml"));
    QDomDocument xml;
    xml.setContent(&zipfile);
    QStringList searchlist;
    searchlist << "office:document-content"
               << "office:body"
               << "office:spreadsheet";
    QDomNodeList n(xml.childNodes());

    for(int i = 0; i < searchlist.count(); ++i)
    {
        int j;
        for(j = 0; j < n.count(); ++j)
        {
            if(n.at(j).nodeName() == searchlist.at(i))
            {
                break;
            }
            if(j == (n.count() - 1))
            {
                return QDomDocument();
            }
        }
        xml = n.at(j);
        n = xml.childNodes();
    }
    return xml;
Aber das funktioniert im moment noch nicht und wird je weiter unten man ist auch immer "fälscher". Kann mir vielleicht jemand ein klares Konzept zeigen wie ich am besten xml Dokumente durchlaufen kann?

Die Funktion soll mir nur die relevante Daten Sektion aus dem xml Dokument zurückgeben, die ich dann mit anderen Funktionen weiter durchsuchen will.

Gruß Thorsten

Verfasst: 8. Dezember 2010 06:33
von Christian81
Wenn man kein DOM braucht dann empfiehlt sich http://doc.trolltech.com/4.7/qxmlstreamreader.html . Dort ist auch ein Beispiel zu finden.

Verfasst: 8. Dezember 2010 10:12
von RHBaum
Kann mir vielleicht jemand ein klares Konzept zeigen wie ich am besten xml Dokumente durchlaufen kann?
Das XML ne hirarische Struktur hat, hasst ja sicher mitbekommen :-)

Die Frage ist, WONACH genau suchst Du. Und daraus leitet sich das WIE ab.

Beispiel: In 99,9999999% Aller Faelle weisst du, oder musst Du, die genaue Position in der Hirarchie kennen. Das Heisst Du hasst die Info, dass dein gesuchtes Element z.b. im Dokument unter NodeEbene1_A->NodeEbene2_C->NodeEbene3_B ... zu finden ist.
Dementsprechend Laesst du dir das Dokument geben (was gleichzeitig nen Node ist) , dort holst Dir das SubElement NodeEbene1_A. Von dem holst Dir NodeEbene2_C von dem NodeEbene3_B usw. bis halt dein element hasst.
Schluesselfunktion ist hier QDomNode::firstChildElement

in 0,00000001% der Faelle weisst nicht, wo in der Hirarchie liegt was suchst, sondern weisst nur das das ding nen eindeutigen Namen hat.
Dann isst es wie wenn Du nen komplettes directory nach einer Datei durchsuchst. Eventuell rekursiver ansatz !

Ciao ...

Verfasst: 8. Dezember 2010 14:21
von surfhai
ok, das ist Praktisch... ich glaub mit QXmlStreamReader komm ich eher klar als mit QDomDocument.

Aber ich möchte dennoch verstehn wie man das auch mit QDomDocument bewältigt. Mein Code is doch nich so ganz falsch, er sollte das 99% Beispiel sein. Das einzige was nicht funktioniert ist die Zuweisung des gefundenen Teilstücks des Dokuments um darin eine Ebene weiter zu suchen.
Dieses Stück code funktioniert nicht wie es soll

Code: Alles auswählen

        xml = n.at(j)
Wenn das ausgeführt wird ist die Variable xml quasi leer. Auch wenn ich das hier Probiere:

Code: Alles auswählen

        xml = n.at(j).toDocument()
Das heißt also das ich das so nicht machen kann. Könnte das jemand zum laufen bringen? Die herangehensweise ist wahrscheinlich hier schon falsch und wie ich die Klassen einsetze.

Verfasst: 8. Dezember 2010 15:50
von RHBaum
Warum QDomDocument als Rueckgabewert ?

Nen DOMDocument repraesentiert nen komplettes XML dokument, inclusive allen versions und formatierungs-infos etc.

Du willst aber nur nen "Teilstücks des Dokuments" zurueckgeben ... und kein komplett ausformuliertes XML-Dokument.

QDomNode - wenn ne Position in der Hirarchie brauchst
QDomElement - wenn sicher bist das es ein Elementeintrag ist und du die Attribute zu brauchst.

QDomElement ist eine spezialisierung von QDOMNode !

Ciao ...

Verfasst: 8. Dezember 2010 16:25
von upsala
Und alternativ kann man auch QXmlQuery benutzen, wenn man sich mit XQuery bzw. XPath auskennt.

Verfasst: 9. Dezember 2010 16:31
von surfhai
Hab das ganze jetzt mal mit QXmlStreamReader versucht. Das Programm stürzt aber komischerweise ab und ich hab keine Ahnung warum.

project.pro

Code: Alles auswählen

QT       += core gui xml

TARGET = project
TEMPLATE = app
DEPENDPATH += . quazip
INCLUDEPATH += . quazip

SOURCES += main.cpp\
    thread.cpp \
    utils.cpp

HEADERS  += thread.h \
    utils.h

include(quazip/quazip.pri)
main.cpp

Code: Alles auswählen

#include <QtGui/QApplication>
#include "utils.h"
#include "thread.h"
#include <QString>
#include <QDebug>
#include <QXmlStreamReader>

int main(int argc, char *argv[])
{
    QXmlStreamReader * xml = new QXmlStreamReader();
    xml = Utils::readODS(QString("threads.ods"));
    Thread * x = new Thread(xml, QString("metrisch"));
    return 0;
    }

}
thread.h

Code: Alles auswählen

#ifndef THREAD_H
#define THREAD_H

#include <QObject>
#include <QString>
#include <QXmlStreamReader>

class Thread : public QObject
{
    Q_OBJECT
public:
    explicit Thread(QXmlStreamReader * xml, QString threadType, QObject *parent = 0);
    explicit Thread(const Thread &, QObject *parent = 0);

signals:

public slots:

private:
    double dataP;
    double dataD;
    QString type;
    qint64 startLineNumber;
    QXmlStreamReader * xml;

};

#endif // THREAD_H
thread.cpp

Code: Alles auswählen

#include "thread.h"
#include <QXmlStreamReader>
#include <QDebug>

Thread::Thread(QXmlStreamReader * xml, QString threadType, QObject *parent) :
    QObject(parent)
{
    type = threadType;
    while(!xml->atEnd())
    {
        xml->readNext();
        if(xml->name().toString() == "table" &&
           xml->isStartElement() &&
           xml->attributes().value("name").toString() == type)
        {
            startLineNumber = xml->lineNumber();
            qDebug() << type;
        }
    }
    if (xml->hasError())
    {
        qDebug() << "Error" << xml->error()
                 << xml->errorString();
        qDebug() << "at line number " << xml->lineNumber();
        qDebug() << "at column number " << xml->columnNumber();
        qDebug() << "at character offset " << xml->characterOffset();
    }
}

Thread::Thread(const Thread& t, QObject *parent):
        QObject(parent)
{
    type = t.type;
    xml = t.xml;
    dataP = t.dataP;
    dataD = t.dataD;
}
utils.h

Code: Alles auswählen

#ifndef READODS_H
#define READODS_H

#include <QString>
#include <QXmlStreamReader>
#include <quazip.h>
#include <quazipfile.h>

class Utils
{
  public:
    Utils();
    static QXmlStreamReader * readODS(QString filepath);
};

#endif // READODS_H
utils.cpp

Code: Alles auswählen

#include "utils.h"

#include <QString>
#include <QDebug>
#include <QXmlStreamReader>
#include <QXmlStreamAttributes>
#include <quazip.h>
#include <quazipfile.h>


Utils::Utils()
{
}

QXmlStreamReader *
Utils::readODS(QString filepath)
{
    QuaZipFile zipfile;
    zipfile.setZipName(filepath);
    zipfile.setFileName(QString("content.xml"));
    zipfile.open(QIODevice::ReadOnly);
    QXmlStreamReader * xml = new QXmlStreamReader(&zipfile);
    return xml;
}
compiler output

Code: Alles auswählen

Führe Build-Schritte für Projekt project aus...
Unveränderte Konfiguration, qmake-Schritt wird übersprungen.
Starte "/usr/bin/make" -w
make: Entering directory `/home/tg/Dokumente/Entwicklung/C++/project-build-desktop'
g++ -c -m64 -pipe -g -Wall -W -D_REENTRANT -DQT_XML_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt/mkspecs/linux-g++-64 -I../project -I/usr/include/QtCore -I/usr/include/QtGui -I/usr/include/QtXml -I/usr/include -I../project -I../project/quazip -I. -I. -I. -o thread.o ../project/thread.cpp
g++ -m64 -Wl,--hash-style=gnu -Wl,--as-needed -o project main.o thread.o utils.o ioapi.o JlCompress.o quaadler32.o quacrc32.o quazip.o quazipfile.o quazipnewinfo.o unzip.o zip.o moc_thread.o moc_quazipfile.o    -L/usr/lib -lQtXml -lQtGui -lQtCore -lpthread 
make: Leaving directory `/home/tg/Dokumente/Entwicklung/C++/project-build-desktop'
Der Prozess "/usr/bin/make" wurde normal beendet.
Ausgabe

Code: Alles auswählen

Starte /home/tg/Dokumente/Entwicklung/C++/project-build-desktop/project...
Das Programm ist abgestürzt.
/home/tg/Dokumente/Entwicklung/C++/project-build-desktop/project beendet, Rückgabewert 0
Backtrace

Code: Alles auswählen

Thread 1 (Thread 0x7ffff7fab760 (LWP 14412)):
#0  0x00007fffffffe7b5 in ?? ()
#1  0x00007ffff6db37e6 in QIODevice::read(char*, long long) () from /usr/lib/libQtCore.so.4
#2  0x00007ffff6e60cc3 in ?? () from /usr/lib/libQtCore.so.4
#3  0x00007ffff6e61148 in ?? () from /usr/lib/libQtCore.so.4
#4  0x00007ffff6e6136e in ?? () from /usr/lib/libQtCore.so.4
#5  0x00007ffff6e6feff in QXmlStreamReader::readNext() () from /usr/lib/libQtCore.so.4
#6  0x00000000004065f7 in Thread::Thread (this=0x61cf30, xml=0x61e590, threadType=..., parent=0x0) at ../project/thread.cpp:20
#7  0x0000000000405e48 in main (argc=1, argv=0x7fffffffe078) at ../project/main.cpp:22

Verfasst: 9. Dezember 2010 16:53
von Christian81
Und mal wieder mangelhafte C Grundkenntnisse - heute schon der zweite Beitrag ... :(
Wie lange lebt zipfile ?

Verfasst: 9. Dezember 2010 19:51
von surfhai
Gut das du bei dem Fehler nicht erblindet bist :D
Ist mir nicht aufgefallen, dass zipfile so lang überleben muss. Wenn das so ist kann ich die Klasse Utils gleich ganz wegfallen lassen.

Danke für den Hinweis, ich hätte mich zu tode gesucht.