Seite 1 von 1
XML auslesen
Verfasst: 30. April 2007 15:45
von mathies
Hallo,
das Thema wurde zwar schon ein paar Mal angeschnitten aber noch nie richtig geklärt und die Antworten sind alles andere als zufriedenstellend, daher meine Frage.
Wie lese ich eine XML-Datei mit Qt aus? Die Beispiele bei Qt sind unbrauchbar, da diese nicht mal eine simple XML auslesen können, wenn diese nicht ihrem "Standard" entspricht.
Wenn z.B. eine solche Struktur gegeben ist (es kann natürlich mehrere Sektionen geben und mehrere Infos im InfoSet):
Code: Alles auswählen
<Konfiguration>
<Sektion>
<Name>MalerInfos</Name>
<Kommentar>Informationen für Maler</Kommentar>
<InfoSet>
<Info>
<Einheit>Blau</Einheit>
<Datum>01.01.2007</Datum>
<Beschreibung>Alles gruen machen</Beschreibung>
</Info>
</InfoSet>
</Sektion>
</Konfiguration>
Mit Xerces ging das prima und die Beispiele waren zu gebrauchen aber bei Qt hakt es ein bissl. Ich kann halt nur Xerces nicht nehmen, daher bräuchte ich mal eine Lösung mit Qt.
Wie muss ich z.B eine Schleife aufbauen um eine Sektion nach der anderen zu betrachten. Man kann sich keine vernünftige NodeList eines Elements geben lassen, alles nur mit definierten Namen aber die können sich ja nun auch mal ändern.
Wäre echt super wenn jemand mal ein kleines Beispiel posten könnte mit zwei, drei Ebenen im XML.
Grüßle,
Matthias
Verfasst: 30. April 2007 15:52
von piXelshooter
damit wollte ich mich auch grad beschäftigen, aber nur so nebenbei, du weißt schon von dem Modul QtXml?
Ich seh mir das grad an, kann dir ja dann vllt was dazu sagen

Verfasst: 30. April 2007 16:29
von upsala
Die Beispiele hier sollte eigentlich ausreichend sein:
QDomDocument
Verfasst: 30. April 2007 16:45
von mathies
Hallochen,
hab das schon alles eingebunden und und habe die XML-Datei auch schon übergeben aber dann ist finish, das heißt mir fehlt der gesamte Informationszugriff.
Und mit der Doku komm ich net klar, hatte mir das schon alles mal angetan. Bei mir kann es z.B. mehrere Sektionen geben und im Beispiel holen die sich immer nur den ersten Kindknoten - super, wie gehts denn dann weiter? Und soll ich dann bei jedem Eintrag probieren den zu einem Element zu konvertieren? Das kann doch nicht Sinn und Zweck der Sache sein. Und wie ich an die Infos an sich komme, geht daraus auch nicht hervor. Ich finde die Doko, zum ersten Mal übrigens, richtig bescheiden!
Grüßle,
Matthias
Verfasst: 30. April 2007 17:29
von upsala
Du hast
bzw.
Code: Alles auswählen
QDomElement QDomNode::nextSiblingElement ( const QString & tagName = QString() ) const
überlesen.
Außerdem ist die Qt-Doku nicht dazu da um dir
DOM zu erklären, sondern wie man es mit Qt handhabt...
Verfasst: 30. April 2007 17:41
von mathies
Vollkommen richtig. Nichts desto trotz kann man ein Beispiel wählen, welches einleuchtend ist. Weiterhin braucht mir die Doku nicht Dom zu erklären, nur die Umsetzung dessen muss schon ersichtlich sein. Somit wäre ne bessere Erläuterung schon was wert - bei Apache klappts doch auch.
Dank Dir trotzdem, werd des mal so testen.
Verfasst: 1. Mai 2007 11:18
von andy72
Habe eben mal mit QtDomDocument gespielt, hat jemand auch diesen Fehler ?
Code: Alles auswählen
#include <QDomDocument>
#include <QDomNodeList>
#include <QDomNode>
#include <iostream>
using std::cout;
using std::endl;
int main(int arc, char **argv) {
QDomDocument doc;
QFile file("filename.xml";
if(!file.open(QIODevice::ReadOnly))
return;
if(!doc.setContent(&file)) {
file.close();
return;
}
file.close();
QDomNode node;
QDomNode child;
QDomNodeList list = doc.getElementsByTagName("mytagname");
for(int i = 0; i < list.size(); i++) {
node = list.at(i);
child = node->firstChild();
cout << child.nodeName().toStdString() << endl;
}
return 0;
}
Beim Kompilieren mit qmake -project, qmake, make kommt einCompiler-Error, dass sämtliche includes vom Qt nicht gefunden werden können.
Nach etwas suchen stellte sich heraus, dass die Header gar nicht da sind, sondern sich genutzte Objects in Qt/qdom.h befinden.
Nachdem ich das dann gefixed habe, kommt ein weiterer Compiler-Error, der sich dann über fehlende Linkage beschwert: qmake "vergisst", im Makefile die Library "libQtXml.so" mit einzubinden.
Ich nutze Qt-4.2.3 - wäre nett, wenn jemand das mal nach vollziehen könnte, oder ob ich evtl. eine Fehlerhafte Installation (unter Linux) habe.
LG
Andy
Verfasst: 1. Mai 2007 11:29
von Christian81
RTFM!
http://doc.trolltech.com/4.2/qtxml.html#details
To include the definitions of the module's classes, use the following directive:
#include <QtXml>
To link against the module, add this line to your qmake .pro file:
QT += xml
Ist es so schwer ne Doku zu lesen? Jedesmal das Gleiche...

Verfasst: 1. Mai 2007 11:46
von andy72
Sicher ist das nicht so schwer, ich habe lediglich das Beispiel aus der Qt-Doku genommen,um einen start zu haben wie man mit QtDomDocument umgeht. im Beispiel ist von diesem Include leider keine Rede

Verfasst: 1. Mai 2007 11:55
von Christian81
Ich meine ja auch nicht das include sondern eher die config-Option.
qmake -project ist nunmal nur dazu da ein generisches .pro-File zu erstellen was man selbst von Hand weiterbearbeiten muss.
Das Include würde ich nicht nehmen - nur wenn man zu faul ist die einzelnen Header zu includen. Geht aber zu Lasten der Kompiliergeschwindigkeit da jedesmal alle Header von QtXml includiert werden.
Verfasst: 2. Mai 2007 22:13
von Brownie
Huhu,
vielleicht hilft dir folgender Link zu Xml und Qt auch noch weiter.
Die Beispiele sind zumindest gut nachzuvollziehen.
http://www.digitalfanatics.org/projects ... ter09.html
Verfasst: 4. Mai 2007 09:22
von C_R
http://qtforum.de/forum/viewtopic.php?t=4105
Ist ein kleines Beispiel von mir. Den Delegate brauchst du erstmal nicht, läuft auch so. Ist aber sehr speziell dieser Beispielcode! Eine XmlFile von mir sieht wie unten aus.
Aufgerufen wird das Model folgendermaßen:
Code: Alles auswählen
// trackSettingsPanel is QTreeView
QFile file(path); // path is relative to currentPath() (programs dir)
if (file.open(QIODevice::ReadWrite)) {
QDomDocument document;
if (document.setContent(&file)) {
XmlModel *newModel = new XmlModel(document, mode, this); // xml model file
trackSettingsPanel->setModel(newModel); // apply model
CustomXmlDelegate *delegate = new CustomXmlDelegate(1, this);
trackSettingsPanel->setItemDelegate(delegate);
delete xmlModel;
xmlModel = newModel; // overwrite model (member)
}
file.close();
}
Code: Alles auswählen
<?xml version="1.0"?>
<satpred job="track">
<global>
<entry name="name01">
<value>val01</value>
<comment>comment01</comment>
</entry>
<entry name="name02">
<value>val02</value>
<comment>comment02</comment>
</entry>
<entry name="name03">
<value>val03</value>
<comment>comment03</comment>
</entry>
<entry name="name04">
<entry name="name41">
<value>val41</value>
<comment>comment41</comment>
</entry>
<comment>comment04</comment>
</entry>
</global>
<track>
<entry name="track">
<value>wert</value>
<comment>kommentar</comment>
</entry>
</track>
</satpred>
Verfasst: 4. Mai 2007 11:54
von patrik08
es geht auch mit iterator durch das ganze file runter rekursiv ... mit wenig schreibarbeit!
ich benutze so was um alle paragraf auszulesen von einem xhtml file... ohne nur eine regular expression zu schreiben.... dann habe ich den puren text aus dem html
Code: Alles auswählen
QDomDocument doc;
doc.setContent(XMLSTREAM);
DomElementContainer c(doc, "tag");
foreach(QDomElement e, c) {
if (e.tagName() == "tagnamex" ) {
qDebug("%s", qPrintable(e.text()));
}
}
Code: Alles auswählen
class DomElementContainer {
public:
class const_iterator {
friend class DomElementContainer;
public:
const_iterator(){}
const_iterator &operator++(){
m_e = m_e.nextSiblingElement(m_t);
return *this;
}
const QDomElement & operator*(){
return m_e;
}
bool operator==(const const_iterator &other) const {
return (m_e==other.m_e && m_t==other.m_t);
}
bool operator!=(const const_iterator &other) const {
return (m_e!=other.m_e || m_t!=other.m_t);
}
private:
const_iterator(const QDomElement &e, const QString &t){
m_e = e;
m_t = t;
}
QDomElement m_e;
QString m_t;
};
DomElementContainer(const QDomElement &e, const QString &tag=QString::null){
m_tag = tag;
m_elem = e;
}
DomElementContainer(const QDomDocument &d, const QString &tag=QString::null){
m_tag = tag;
m_elem = d.documentElement();
}
const_iterator begin() const{
return const_iterator(m_elem.firstChildElement(m_tag), m_tag);
}
const_iterator end() const {
return const_iterator(QDomElement(), m_tag);
}
private:
QDomElement m_elem;
QString m_tag;
};
qxml.h
Code: Alles auswählen
#ifndef QXML_H
#define QXML_H
/* save this file as qxml.h dont forget to set QT += xml on your pro file */
#include <QDomDocument>
#include <QtDebug>
#include <QDebug>
#include <QSettings>
#include <QDomDocument>
#include <QDomElement>
#include <QDomImplementation>
#include <QDomProcessingInstruction>
#include <QFile>
#include <QTextCodec>
#include <QString>
/*
sample read :
Qxml doc;
doc.SetSelf( const QString fullFileName );
QDomElement root = doc.root();
new doc
Qxml doc;
doc.SetstreamFile( QString sfile );
QDomElement root = doc.root();
append to root
#include "domelementcontainer.h"
const char *xml = "<test><tag>content 1</tag><tag>content 2</tag> "
"<othertag>wrongcontent</othertag>"
"<tag>content 3</tag></test>";
int main(){
QDomDocument doc;
doc.setContent(XMLSTREAM);
DomElementContainer c(doc, "tag");
foreach(QDomElement e, c)
qDebug("%s", qPrintable(e.text()));
return 0;
}
from http://www.qtcentre.org/ amministrator;
http://blog.wysota.eu.org/ http://www.wysota.eu.org/
*/
class DomElementContainer {
public:
class const_iterator {
friend class DomElementContainer;
public:
const_iterator(){}
const_iterator &operator++(){
m_e = m_e.nextSiblingElement(m_t);
return *this;
}
const QDomElement & operator*(){
return m_e;
}
bool operator==(const const_iterator &other) const {
return (m_e==other.m_e && m_t==other.m_t);
}
bool operator!=(const const_iterator &other) const {
return (m_e!=other.m_e || m_t!=other.m_t);
}
private:
const_iterator(const QDomElement &e, const QString &t){
m_e = e;
m_t = t;
}
QDomElement m_e;
QString m_t;
};
DomElementContainer(const QDomElement &e, const QString &tag=QString::null){
m_tag = tag;
m_elem = e;
}
DomElementContainer(const QDomDocument &d, const QString &tag=QString::null){
m_tag = tag;
m_elem = d.documentElement();
}
const_iterator begin() const{
return const_iterator(m_elem.firstChildElement(m_tag), m_tag);
}
const_iterator end() const {
return const_iterator(QDomElement(), m_tag);
}
private:
QDomElement m_elem;
QString m_tag;
};
class Qxml : public QDomDocument
{
public:
Qxml(); /* utf-8 - ISO-8859-1 */
QString decode;
inline QString Getdecode() { return decode; }
bool SetSelf( const QString fullFileName );
QDomElement insertFragmentorFile( QString fragment ); /* insert xml file or tag fragment */
QString StringtoXML( QString t ); /* xml_escape_chars */
void SetstreamFile( QString sfile ); /* set a work file */
bool saveXML(const QString fullFileName); /* save to external file */
bool saveXML(); /* save to work file if exist */
void Print(); /* print to console */
QString GetAtt(QDomElement e , QString name ); /* get attribute value from element */
QDomElement root();
QString FilterAttribute( QDomElement element , QString attribute );
QDomElement insertTagValue( const QString name , QString value );
protected:
bool is_file(QString fullFileName);
bool xml_unlink(QString fullFileName);
private:
QDomProcessingInstruction header;
QString stream_on_file;
QDomElement ErrorDom(); /* on error return </error> tag */
};
//
#endif // QXML_H
qxml.cpp
Code: Alles auswählen
#include "qxml.h"
/* save this file as qxml.cpp */
/* constructor */
Qxml::Qxml()
{
decode = "utf-8";
header = QDomDocument::createProcessingInstruction( "xml",QString("version=\"1.0\" encoding=\"%1\"" ).arg(decode));
appendChild( header );
}
QDomElement Qxml::root()
{
QDomElement root = documentElement();
return root;
}
bool Qxml::SetSelf( const QString fullFileName )
{
QString errorStr;
int errorLine, errorColumn, position;
QFile f( fullFileName );
if ( !f.exists(fullFileName) ) {
return false;
}
if(!f.open(QIODevice::ReadOnly)) {
return false;
}
/* no namen space ! */
if (!setContent(&f,false, &errorStr, &errorLine, &errorColumn)) {
return false;
} else {
return true;
}
}
/* save doc if is a streamfiele */
bool Qxml::saveXML()
{
if (is_file(stream_on_file)) {
return saveXML(stream_on_file);
}
return false;
}
/* print on cosole the result */
void Qxml::Print()
{
QTextStream out(stdout);
out << Qxml::toString();
}
QDomElement Qxml::insertTagValue( const QString name , QString value )
{
QDomElement yourtag = QDomDocument::createElement( name );
////QDomNode::setNodeValue( value ) ;
yourtag.appendChild(Qxml::createTextNode(value));
return yourtag;
}
/* Append fragment or a real xml file */
QDomElement Qxml::insertFragmentorFile( QString fragment )
{
bool check;
/* if is a file insert dom tree and convert to element */
if (is_file(fragment)) {
QFile ext_file(fragment);
ext_file.open( QIODevice::ReadOnly);
QDomDocument dom_external;
check = dom_external.setContent(&ext_file);
if ( check ) {
QDomElement root_extern = dom_external.documentElement();
QDomNode newnode = root_extern.firstChild();
QDomNode treallsub = dom_external.importNode(newnode,true);
ext_file.close();
return treallsub.toElement();
} else {
ext_file.close();
return ErrorDom();
}
} else {
/* is not a file */
QTextCodec *setcurrentcodec;
if (decode == "utf-8") {
setcurrentcodec = QTextCodec::codecForMib(106); /* utf8 */
} else {
setcurrentcodec = QTextCodec::codecForMib(4); /* latin iso */
}
if (stream_on_file.size() > 0) {
QFile f( stream_on_file );
if ( f.open( QFile::WriteOnly | QFile::Text ) ) {
QTextStream sw( &f );
sw.setCodec(setcurrentcodec);
sw << QString("<?xml version=\"1.0\"?>\n<dummyroot>%1</dummyroot>").arg(fragment);
f.close();
if (is_file(stream_on_file)) {
return insertFragmentorFile(stream_on_file);
}
}
}
return ErrorDom();
}
}
/* return on error an error tag */
QDomElement Qxml::ErrorDom()
{
QDomElement errorelement = QDomDocument::createElement( "error" );
return errorelement;
}
/* setup a file to stream fragments */
void Qxml::SetstreamFile( QString sfile )
{
stream_on_file = sfile;
}
QString Qxml::StringtoXML( QString t )
{
//the following checks are necessary before exporting
//strings to XML. see http://hdf.ncsa.uiuc.edu/HDF5/XML/xml_escape_chars.html for details
QString text = t;
text.replace("&", "&"); /* qt4 toUtf8 dont replace && */
text.replace("\"",""");
text.replace("'", "'");
text.replace("<", "<");
text.replace(">", ">");
text.replace("\n", "
");
text.replace("\r", "
");
return text;
}
/* save to a specific file */
bool Qxml::saveXML( const QString fullFileName )
{
QTextCodec *setcurrentcodec;
if (decode == "utf-8") {
setcurrentcodec = QTextCodec::codecForMib(106); /* utf8 */
} else {
setcurrentcodec = QTextCodec::codecForMib(4); /* latin iso */
}
QFile f( fullFileName );
if ( f.open( QFile::WriteOnly | QFile::Text ) ) {
QTextStream sw( &f );
sw.setCodec(setcurrentcodec);
sw << Qxml::toString();
f.close();
if (is_file(fullFileName)) {
return true;
}
}
return false;
}
/* remove file */
QString Qxml::GetAtt(QDomElement e , QString name )
{
QString textvalue;
QString errorvalue = "";
QDomAttr a1 = e.attributeNode(name);
textvalue = a1.value();
if (textvalue.size() > 0) {
return textvalue;
} else {
return errorvalue;
}
}
/* loop to find attribute name xx */
QString Qxml::FilterAttribute( QDomElement element , QString attribute )
{
QString base = "error";
QDomNamedNodeMap attlist = element.attributes();
int bigint = attlist.count();
if ( bigint > 0 ) {
for (int i=0; i<bigint; i++){
QDomNode nod = attlist.item(i);
if (nod.nodeName() == attribute) {
base = QString(nod.nodeValue());
return base;
}
}
}
return base;
}
/* checker if is file exist */
bool Qxml::is_file(QString fullFileName)
{
QFile f( fullFileName );
if ( f.exists() ) {
return true;
} else {
return false;
}
}
/* remove file */
bool Qxml::xml_unlink(QString fullFileName)
{
QFile f( fullFileName );
if ( is_file( fullFileName ) ) {
if (f.remove()) {
return true;
}
}
return false;
}