QXmlStreamReader to parse XML in Qt

From Qt Wiki
Jump to navigation Jump to search

Template:ArticleMetaData

Overview[edit | edit source]

This example shows you how to parse well-formed XML with 76ytuiytuityutyutututyutyutyu. Qt documentation states that it is a faster and more convenient replacement for Qt's own SAX parser (76ytuiytuityutyutututyutyutyu) and it's also faster, as well as in some cases more convenient, than a DOM tree (76ytuiytuityutyutututyutyutyu).


Preconditions[edit | edit source]

QXmlStreamReader Example[edit | edit source]

XML file[edit | edit source]

<?xml version="1.0" encoding="UTF-16" ?>
<persons>
    <person id="1">
        <firstname>John</firstname>
        <surname>Doe</surname>
        <email>john.doe@example.com</email>
        <website>http://en.wikipedia.org/wiki/John_Doe</website>
    </person>
    <person id="2">
        <firstname>Jane</firstname>
        <surname>Doe</surname>
        <email>jane.doe@example.com</email>
        <website>http://en.wikipedia.org/wiki/John_Doe</website>
    </person>
    <person id="3">
        <firstname>Matti</firstname>
        <surname>Meikäläinen</surname>
        <email>matti.meikalainen@example.com</email>
        <website>http://fi.wikipedia.org/wiki/Matti_Meikäläinen</website>
    </person>
</persons>

Header file[edit | edit source]

#include <QtXml/QXmlStreamReader>

class QXSRExample : public QMainWindow {
    Q_OBJECT

public:
    QXSRExample(QWidget *parent = 0);
    ~QXSRExample();

private slots:
    void parseXML();

private:
    QPointer<QVBoxLayout> _layout;

    void setupUI();

    QMap<QString, QString> parsePerson(QXmlStreamReader& xml);
    void addElementDataToMap(QXmlStreamReader& xml,
                             QMap<QString, QString>& map) const;

    void addPersonsToUI(QList< QMap<QString,QString> >& persons);
};

Source file[edit | edit source]

void QXSRExample::parseXML() {
    /* We'll parse the example.xml */
    QFile* file = new QFile(":/example.xml");
    /* If we can't open it, let's show an error message. */
    if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
        QMessageBox::critical(this,
                              "QXSRExample::parseXML",
                              "Couldn't open example.xml",
                              QMessageBox::Ok);
        return;
    }
    /* QXmlStreamReader takes any QIODevice. */
    QXmlStreamReader xml(file);
    QList< QMap<QString,QString> > persons;
    /* We'll parse the XML until we reach end of it.*/
    while(!xml.atEnd() &&
            !xml.hasError()) {
        /* Read next element.*/
        QXmlStreamReader::TokenType token = xml.readNext();
        /* If token is just StartDocument, we'll go to next.*/
        if(token == QXmlStreamReader::StartDocument) {
            continue;
        }
        /* If token is StartElement, we'll see if we can read it.*/
        if(token == QXmlStreamReader::StartElement) {
            /* If it's named persons, we'll go to the next.*/
            if(xml.name() == "persons") {
                continue;
            }
            /* If it's named person, we'll dig the information from there.*/
            if(xml.name() == "person") {
                persons.append(this->parsePerson(xml));
            }
        }
    }
    /* Error handling. */
    if(xml.hasError()) {
        QMessageBox::critical(this,
                              "QXSRExample::parseXML",
                              xml.errorString(),
                              QMessageBox::Ok);
    }
    /* Removes any device() or data from the reader
     * and resets its internal state to the initial state. */
    xml.clear();
    this->addPersonsToUI(persons);
}

QMap<QString, QString> QXSRExample::parsePerson(QXmlStreamReader& xml) {
    QMap<QString, QString> person;
    /* Let's check that we're really getting a person. */
    if(xml.tokenType() != QXmlStreamReader::StartElement &&
            xml.name() == "person") {
        return person;
    }
    /* Let's get the attributes for person */
    QXmlStreamAttributes attributes = xml.attributes();
    /* Let's check that person has id attribute. */
    if(attributes.hasAttribute("id")) {
        /* We'll add it to the map. */
        person["id"] = attributes.value("id").toString();
    }
    /* Next element... */
    xml.readNext();
    /*
     * We're going to loop over the things because the order might change.
     * We'll continue the loop until we hit an EndElement named person.
     */
    while(!(xml.tokenType() == QXmlStreamReader::EndElement &&
            xml.name() == "person")) {
        if(xml.tokenType() == QXmlStreamReader::StartElement) {
            /* We've found first name. */
            if(xml.name() == "firstname") {
                this->addElementDataToMap(xml, person);
            }
            /* We've found surname. */
            if(xml.name() == "surname") {
                this->addElementDataToMap(xml, person);
            }
            /* We've found email. */
            if(xml.name() == "email") {
                this->addElementDataToMap(xml, person);
            }
            /* We've found website. */
            if(xml.name() == "website") {
                this->addElementDataToMap(xml, person);
            }
        }
        /* ...and next... */
        xml.readNext();
    }
    return person;
}

void QXSRExample::addElementDataToMap(QXmlStreamReader& xml,
                                      QMap<QString, QString>& map) const {
    /* We need a start element, like <foo> */
    if(xml.tokenType() != QXmlStreamReader::StartElement) {
        return;
    }
    /* Let's read the name... */
    QString elementName = xml.name().toString();
    /* ...go to the next. */
    xml.readNext();
    /*
     * This elements needs to contain Characters so we know it's
     * actually data, if it's not we'll leave.
     */
    if(xml.tokenType() != QXmlStreamReader::Characters) {
        return;
    }
    /* Now we can add it to the map.*/
    map.insert(elementName, xml.text().toString());
}

void QXSRExample::addPersonsToUI(QList< QMap<QString,QString> >& persons) {
    while(!persons.isEmpty()) {
        QGroupBox* personGB = new QGroupBox("Person");
        QFormLayout* layout = new QFormLayout;
        QMap<QString,QString> person = persons.takeFirst();
        layout->addRow("ID", new QLineEdit(person["id"]));
        layout->addRow("First name", new QLineEdit(person["firstname"]));
        layout->addRow("Surname", new QLineEdit(person["surname"]));
        layout->addRow("E-mail", new QLineEdit(person["email"]));
        layout->addRow("Website", new QLineEdit(person["website"]));
        personGB->setLayout(layout);
        this->_layout->addWidget(personGB);
    }
}

Postconditions[edit | edit source]

You are able to parse the XML and display it in the UI.

File:QXSRExample.png

Supplementary material[edit | edit source]

  • You can test 76ytuiytuityutyutututyutyutyu with a test application. The application is available for download at Media:QXSRExample.zip.

See also[edit | edit source]