Parse XML in Qt

In Qt, there seem a lot of classes related to XML:QDomDocument, QXmlStreamReader,QXmlSimpleReader,etc. You can choose any one to parse an XML document.  QDomDocument is more powerful but keep all content of xml document in memory. QXmlStreamReader, as the name implies, reads xml document from the beginning to the end sequentially. It does not keep the content read earlier in memory, thus is appropriate for handling large xml file. The speed is also superior to QDomDocument.

The parsing of xml using QDomDocument is typically as follows:

QFile file(xmlfilename);

  QDomDocument dom;
  if(!file.open(QIODevice::ReadOnly))
  {
      QMessageBox::warning(this,"error","no xml");
      return;
  }
  dom.setContent(&file);
  file.close();

  QDomElement rootele=dom.documentElement();
  QDomNodeList	nodelist=rootele.elementsByTagName("Product");
  int num=nodelist.count();
  QDomElement ele;
  int i;
  for(i=0; i<num; i++)
  {
      QDomNode node=nodelist.item(i);
      ele=node.toElement();
      if(ele.isNull())
          continue;
      QString id=ele.elementsByTagName("Id").item(0).toElement().text();
 }

You should associate the xml file with QDomDocument using QDomDocument::setContent. Then, the first thing is to get the root element of the xml document using QDomDocument::documentElement(). The root element,i.e., the document element is what is after the optional line “<?xml version=”1.0″ encoding=”UTF-8″?> ” in the xml file. The line “<?xml version=”1.0″ encoding=”UTF-8″?> ” is called XML prolog. It is not the root element of xml document; it is even not a part of xml document.

Another thing worth noting is QDomElement::elementsByTagName returns a list of dom nodes, not a list of dom elements, which means you should use QDomNode::toElement to convert them to Dom elements. The most often used function is  QDomElement::text, which obtains the text between the open tag and close tag.

The parsing of Xml using QXmlStreamReader is most like the following code:

xmlFile = new QFile("xmlFile.xml");
        if (!xmlFile->open(QIODevice::ReadOnly | QIODevice::Text)) {
                QMessageBox::critical(this,"Load XML File Problem",
                "Couldn't open xmlfile.xml to load settings for download",
                QMessageBox::Ok);
                return;
        }
xmlReader = new QXmlStreamReader(xmlFile);


//Parse the XML until we reach end of it
while(!xmlReader->atEnd() && !xmlReader->hasError()) {
        // Read next element
        QXmlStreamReader::TokenType token = xmlReader->readNext();
        //If token is just StartDocument - go to next
        if(token == QXmlStreamReader::StartDocument) {
                continue;
        }
        //If token is StartElement - read it
        if(token == QXmlStreamReader::StartElement) {

                if(xmlReader->name() == "name") {
                        continue;
                }

                if(xmlReader->name() == "id") {
                    qDebug() << xmlReader->readElementText();
                }
        }
}

if(xmlReader->hasError()) {
        QMessageBox::critical(this,
        "xmlFile.xml Parse Error",xmlReader->errorString(),
        QMessageBox::Ok);
        return;
}

//close reader and flush file
xmlReader->clear();
xmlFile->close();

As you can see, the constructor of  QXmlStreamReader associates the xml file with itself. The core function of QXmlStreamReader is readNext, which reads the next xml tag(i.e.,<…>). Qt calls xml tags as tokens. Note that some QXmlStreamReader functions move forward the read pointer(i.e., readNext(), readElementText(),etc.), while others(i.e., name(), attributes(),etc.)do not, they return something from the data that’s already read. Usually, we use readNext() to get the next tag, then according to the tag type(QXmlStreamReader::StartElement,QXmlStreamReader::StartDocument,QXmlStreamReader::Comment, QXmlStreamReader::ProcessingInstruction, QXmlStreamReader::DTD,etc.), use appropriate functions such as attributes(), name(), text(), etc. to get content from what is contained in the tag.

Posted in

Leave a Reply