Qt - tworzenie, zapisywanie i odczytywanie danych zapisanych w formacie XML

Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 2830 razy

XML (rozszerzony język znaczników) to format zapisu danych w formie tekstu, który jest bardzo często wykorzystywany do zapisu danych. Najbardziej znanym wykorzystaniem tego formatu jest HTML wykorzystywany przez strony internetowe do formatowania danych i wyglądu strony. XML jest także wykorzystywany przez wiele innych aplikacji takich jak np. Inkscape, który do zapisu danych i ich formatowania wykorzystuje w przebiegły sposób format XML. Z tego względu warto wiedzieć co nieco o tym formacie danych i możliwości jego wykorzystania.

Prosty przykład kodu XML

Rzućmy łaskawym okiem na taki oto prosty kawałek kodu:

<movies> <movie title="Red Dragon" year="2002"/> <movie title="Silence of the lambs" year="1991"/> </movies>

Dokumenty XML mają strukturę drzewiastą, co oznacza, że:

Warto też wiedzieć, że każda gałąź czy korzeń ma swoją nazwę oraz atrybuty. Nazwą korzenia dokumentu z powyższego kodu jest movies, korzeń ten nie ma atrybutów, natomiast atrybuty posiadają gałęzie o nazwie movie, nazwy atrybutów tychże gałęzi to:

Można by rozszerzyć powyższy dokument np do takiej postaci:

<movies> <movie title="Red Dragon" year="2002"> <actors> <actor name="Anthony Hopkins" role="Dr Hannibal Lecter"/> <actor name="Edward Norton" role="Will Graham"/> </actors> </movie> <movie title="Silence of the lambs" year="1991"/> </movies>

W tym przypadku film "Red Dragon" ma gałąź actors (aktorzy) a ta zawiera kolejne gałęzie przechowujące informacje o aktorach i ich rolach.

Przykładowa implementacja odczytu, edycji i zapisu danych XML

Zróbmy sobie mały projekcik bazy danych filmów. Ograniczę się tutaj do minimalnej liczby elementów ponieważ chodzi mi jedynie o pokazanie jak w Qt można tworzyć, wczytywać i zapisywać dane XML. W tym celu konieczne będzie wykorzystanie następujących klas dostępnych w Qt:

Klasa, która będzie zajmowała się obsługą bazy danych nazwana została przeze mnie MovieDatabase, a jej deklaracja w pliku moviesdatabase.h wygląda następująco:

#ifndef MOVIESDATABASE_H #define MOVIESDATABASE_H #include <QObject> #include <QFile> #include <QTextStream> #include <QtXml/QtXml> class MoviesDatabase : public QObject { Q_OBJECT QDomDocument document; QDomElement root; QString filePath; public: explicit MoviesDatabase(const QString &filePath, QObject *parent = 0); void addMovie(const QString &title, uint year); bool exists(const QString &title, uint year); void save(); void writeMovies(); signals: public slots: }; #endif // MOVIESDATABASE_H

W pliku moviesdatabase.cpp kod klasy:

#include "moviesdatabase.h" MoviesDatabase::MoviesDatabase(const QString &filePath, QObject *parent) : QObject(parent), filePath(filePath) { QFile fileOpenXML(filePath); bool allIsLoaded = false; if(fileOpenXML.open(QIODevice::ReadOnly | QIODevice::Text)){ qDebug() << "Database:" << filePath << "opened"; if(document.setContent(&fileOpenXML)){ qDebug() << "Database document readed correctly"; root = document.firstChildElement(); if(root.nodeName() == "movies"){ allIsLoaded = true; } } fileOpenXML.close(); } if(!allIsLoaded){ root = document.createElement("movies"); document.appendChild(root); } } void MoviesDatabase::save(){ QFile fileSaveXML(filePath); if(fileSaveXML.open(QIODevice::WriteOnly | QIODevice::Text)){ fileSaveXML.write(document.toString().toLatin1()); fileSaveXML.close(); } } bool MoviesDatabase::exists(const QString &title, uint year){ QDomNodeList movies = root.elementsByTagName("movie"); QDomElement movie; for(int index = 0; index < movies.count(); index++){ movie = movies.at(index).toElement(); if(movie.attribute("title") == title && movie.attribute("year").toUInt() == year){ return true; } } return false; } void MoviesDatabase::addMovie(const QString &title, uint year){ if(exists(title, year)){ qDebug() << "Film" << title << "z" << year << "roku juz jest w bazie danych"; return ; } QDomElement movie = document.createElement("movie"); movie.setAttribute("title", title); movie.setAttribute("year", year); root.appendChild(movie); } void MoviesDatabase::writeMovies(){ QDomNodeList movies = root.elementsByTagName("movie"); qDebug() << "========================================================================"; qDebug() << "Lista filmow w bazie danych"; qDebug() << "========================================================================"; QDomElement movieElement; for(int i = 0; i < movies.count(); i++){ movieElement = movies.at(i).toElement(); qDebug() << "Tytul:"; qDebug() << movieElement.attribute("title"); qDebug() << "Rok:"; qDebug() << movieElement.attribute("year").toUInt() << "n"; } }

I w końcu użycie tejże klasy w funkcji main:

#include <QCoreApplication> #include "moviesdatabase.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); MoviesDatabase moviesdtb("database.xml"); moviesdtb.addMovie("Red Dragon", 2002); moviesdtb.addMovie("Silence of the lambs", 1991); moviesdtb.writeMovies(); moviesdtb.save(); return a.exec(); }

Wynik działania programu po dwukrotnym jego uruchomieniu powinien być następujący:

Database: "database.xml" opened
Database document readed correctly
Film "Red Dragon" z 2002 roku juz jest w bazie danych
Film "Silence of the lambs" z 1991 roku juz jest w bazie danych
========================================================================
Lista filmow w bazie danych
========================================================================
Tytul:
"Red Dragon"
Rok:
2002

Tytul:
"Silence of the lambs"
Rok:
1991
Strony powiązane
strony powiązane
  1. doc.qt.io/qt-4.8/qdomdocument.html - opis klasy QDomDocument na stronie dokumentacji Qt
  2. doc.qt.io/qt-4.8/qdomelement.html - opis klasy QDomElement na stronie dokumentacji Qt
  3. doc.qt.io/qt-4.8/qdomnode.html - opis klasy QDomNode na stronie dokumentacji Qt
Propozycje książek