Navigation durch xml Dokumente

Alles rund um die Programmierung mit Qt
Antworten
surfhai
Beiträge: 11
Registriert: 5. Dezember 2010 23:54

Navigation durch xml Dokumente

Beitrag 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
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag 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.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag 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 ...
surfhai
Beiträge: 11
Registriert: 5. Dezember 2010 23:54

Beitrag 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.
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag 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 ...
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Und alternativ kann man auch QXmlQuery benutzen, wenn man sich mit XQuery bzw. XPath auskennt.
surfhai
Beiträge: 11
Registriert: 5. Dezember 2010 23:54

Beitrag 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
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Und mal wieder mangelhafte C Grundkenntnisse - heute schon der zweite Beitrag ... :(
Wie lange lebt zipfile ?
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
surfhai
Beiträge: 11
Registriert: 5. Dezember 2010 23:54

Beitrag 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.
Antworten