Retrieving child node values ​​using QXmlItem as the focus of QXmlQuery

I am trying to extract text node values ​​from this xml file:

<!DOCTYPE structure> <data> <x> <id>1</id> <nam>tytuł</nam> <tab>21</tab> <ind>5</ind> <pre>TY</pre> <khw>C.TY</khw> </x> <x> <id>2</id> <nam>autor</nam> <tab>21</tab> <ind>5</ind> <pre>FO</pre> <khw>C.FO</khw> </x> <x> <id>3</id> <nam>hasło korporatywne</nam> <tab>21</tab> <ind>5</ind> <pre>FN</pre> <khw>C.FN</khw> </x> </data> 

What I want to do is get each node and its children and convert it to QMap. I have no problem retrieving a single element, but when it comes to getting children, setting the QXmlQuery result as focus, the QString that I evaluate for the node's child query is empty. I use this piece of code:

 QXmlResultItems results; QFile structure("./structure.xml"); // xml file, as described earlier structure.open(QFile::ReadOnly); QXmlQuery query; query.setFocus(&structure); query.setQuery("data/x"); query.evaluateTo(&results); QXmlItem next = results.next(); while(!next.isNull()) { qDebug() << next.toNodeModelIndex().stringValue(); // everything fine. It prints contents of <x> child nodes QXmlQuery childQuery; QString r; childQuery.setFocus(next); childQuery.setQuery("./nam/text()"); // already tested: "/nam/text()", "/nam/string()", "x/nam/string()", "data/x/nam/string()" etc... still no luck. childQuery.evaluateTo(&r); qDebug() << r; // prints \n but it should print content of <nam> node. next = results.next(); } 

The software I use is: Qt 4.7.2 SDK directly from the Qt website, QtCreator 2.3.1 on Windows and Linux (without any difference in this particular case, the results are the same). I want to be sure that the problem of lack of knowledge, not a software error, please help

+6
source share
4 answers

Unfortunately, it is not clear from the Qt documentation that in cases where you want to use the QXmlQuery::setFocus(const QXmlItem& item) overload to query the child nodes, you must create the corresponding QXmlQuery objects using the QXmlQuery(const QXmlNamePool& np) constructor QXmlQuery(const QXmlNamePool& np) so that they can share the same <object href = "http://qt-project.org/doc/qt-5/qxmlnamepool.html"> QXmlNamePool . Such sharing, simply put, connects requests to each other.

Given this, your example should look like this:

 QFile structure("./structure.xml"); structure.open(QFile::ReadOnly); QXmlQuery query; query.setFocus(&structure); query.setQuery("data/x"); QXmlResultItems results; query.evaluateTo(&results); QXmlQuery childQuery(query.namePool()); while (!results.next().isNull()) { childQuery.setFocus(results.current()); childQuery.setQuery("nam/text()"); QString r; childQuery.evaluateTo(&r); qDebug() << r; } 

Alternatively, you can continue and reuse the starting QXmlQuery object:

 QFile structure("./structure.xml"); structure.open(QFile::ReadOnly); QXmlQuery query; query.setFocus(&structure); query.setQuery("data/x"); QXmlResultItems results; query.evaluateTo(&results); while (!results.next().isNull()) { query.setFocus(results.current()); query.setQuery("nam/text()"); QString r; query.evaluateTo(&r); qDebug() << r; } 
+7
source

Instead of using evaluateTo( QString * ) use the QStringList version. It should work.

+1
source

It should work as follows:

 QDomDocument doc("structure"); QFile file("structure.xml"); if( !file.open( IO_ReadOnly ) ) return -1; if( !doc.setContent( &file ) ) { file.close(); return -2; } file.close(); QDomElement root = doc.documentElement(); if( root.tagName() != "data" ) return -3; QDomNode n = root.firstChild(); while( !n.isNull() ) { QDomElement e = n.toElement(); if( !e.isNull() ) { if( e.tagName() == "x" ) { QMessageBox::information( 0, "X", e.attribute("id", "")+ "\n" + e.attribute("nam", "" ) + "\n" + e.attribute("tab", "")); } } n = n.nextSibling(); } 

The code makes a message box for each x (there is no qt on it, so it cannot check it right now)

0
source

I had the same problem and the solution was to make query and childQuery exactly the same. You can rewrite your code as:

 while(!next.isNull()) { qDebug() << next.toNodeModelIndex().stringValue(); QString r; query.setFocus(next); query.setQuery("./nam/text()"); query.evaluateTo(&r); qDebug() << r; next = results.next(); } 

if childQuery should be in another procedure, you must pass it by reference.

0
source

Source: https://habr.com/ru/post/899476/


All Articles