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

Stronę tą wyświetlono już: 19 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:

Listing 1
  1. <movies>
  2. <movie title="Red Dragon" year="2002"/>
  3. <movie title="Silence of the lambs" year="1991"/>
  4. </movies>

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

  • główny element root (korzeń) w dokumencie morze być tylko jeden, w przypadku powyższego kodu tym korzeniem jest znacznik movies;
  • korzeń morze mieć dowolną liczbę gałęzi, a gałęzie z kolei mogą również zawierać kolejne gałęzie. W przypadku powyższego kodu gałęzie to wszystkie znaczniki movie, które w tym przypadku nie zawierają ani treści ani podgałęzi więc zamknięte są znacznikiem />;

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:

  • title - zawiera tytuł filmu;
  • year - zawiera rok filmu

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

Listing 2
  1. <movies>
  2. <movie title="Red Dragon" year="2002">
  3. <actors>
  4. <actor name="Anthony Hopkins" role="Dr Hannibal Lecter"/>
  5. <actor name="Edward Norton" role="Will Graham"/>
  6. </actors>
  7. </movie>
  8. <movie title="Silence of the lambs" year="1991"/>
  9. </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:

  • QDomDocument - tworzy obiekt dokumentu XML;
  • QDomElement - element drzewa dokumentu;
  • QDomNode - węzeł drzewa dokumentu;
  • QDomNodeList - lista węzłów drzewa dokumentu

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:

Listing 3
  1. #ifndef MOVIESDATABASE_H
  2. #define MOVIESDATABASE_H
  3. #include <QObject>
  4. #include <QFile>
  5. #include <QTextStream>
  6. #include <QtXml/QtXml>
  7. class MoviesDatabase : public QObject
  8. {
  9. Q_OBJECT
  10. QDomDocument document;
  11. QDomElement root;
  12. QString filePath;
  13. public:
  14. explicit MoviesDatabase(const QString &filePath, QObject *parent = 0);
  15. void addMovie(const QString &title, uint year);
  16. bool exists(const QString &title, uint year);
  17. void save();
  18. void writeMovies();
  19. signals:
  20. public slots:
  21. };
  22. #endif // MOVIESDATABASE_H

W pliku moviesdatabase.cpp kod klasy:

Listing 4
  1. #include "moviesdatabase.h"
  2. MoviesDatabase::MoviesDatabase(const QString &filePath, QObject *parent) : QObject(parent), filePath(filePath)
  3. {
  4. QFile fileOpenXML(filePath);
  5. bool allIsLoaded = false;
  6. if(fileOpenXML.open(QIODevice::ReadOnly | QIODevice::Text)){
  7. qDebug() << "Database:" << filePath << "opened";
  8. if(document.setContent(&fileOpenXML)){
  9. qDebug() << "Database document readed correctly";
  10. root = document.firstChildElement();
  11. if(root.nodeName() == "movies"){
  12. allIsLoaded = true;
  13. }
  14. }
  15. fileOpenXML.close();
  16. }
  17. if(!allIsLoaded){
  18. root = document.createElement("movies");
  19. document.appendChild(root);
  20. }
  21. }
  22. void MoviesDatabase::save(){
  23. QFile fileSaveXML(filePath);
  24. if(fileSaveXML.open(QIODevice::WriteOnly | QIODevice::Text)){
  25. fileSaveXML.write(document.toString().toLatin1());
  26. fileSaveXML.close();
  27. }
  28. }
  29. bool MoviesDatabase::exists(const QString &title, uint year){
  30. QDomNodeList movies = root.elementsByTagName("movie");
  31. QDomElement movie;
  32. for(int index = 0; index < movies.count(); index++){
  33. movie = movies.at(index).toElement();
  34. if(movie.attribute("title") == title && movie.attribute("year").toUInt() == year){
  35. return true;
  36. }
  37. }
  38. return false;
  39. }
  40. void MoviesDatabase::addMovie(const QString &title, uint year){
  41. if(exists(title, year)){
  42. qDebug() << "Film" << title << "z" << year << "roku juz jest w bazie danych";
  43. return ;
  44. }
  45. QDomElement movie = document.createElement("movie");
  46. movie.setAttribute("title", title);
  47. movie.setAttribute("year", year);
  48. root.appendChild(movie);
  49. }
  50. void MoviesDatabase::writeMovies(){
  51. QDomNodeList movies = root.elementsByTagName("movie");
  52. qDebug() << "========================================================================";
  53. qDebug() << "Lista filmow w bazie danych";
  54. qDebug() << "========================================================================";
  55. QDomElement movieElement;
  56. for(int i = 0; i < movies.count(); i++){
  57. movieElement = movies.at(i).toElement();
  58. qDebug() << "Tytul:";
  59. qDebug() << movieElement.attribute("title");
  60. qDebug() << "Rok:";
  61. qDebug() << movieElement.attribute("year").toUInt() << "n";
  62. }
  63. }

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

Listing 5
  1. #include <QCoreApplication>
  2. #include "moviesdatabase.h"
  3. int main(int argc, char *argv[])
  4. {
  5. QCoreApplication a(argc, argv);
  6. MoviesDatabase moviesdtb("database.xml");
  7. moviesdtb.addMovie("Red Dragon", 2002);
  8. moviesdtb.addMovie("Silence of the lambs", 1991);
  9. moviesdtb.writeMovies();
  10. moviesdtb.save();
  11. return a.exec();
  12. }

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

Komentarze