How do I run XPath queries in QT?
c++, qt, xpath
Solution
The relevant documentation is at: http://qt-project.org/doc/qt-4.8/qxmlquery.html#running-xpath-expressions.
The solution I came to was to use QXmlQuery to generate an XML file then parse it again using QDomDocument.
RhythmboxTrackModel::RhythmboxTrackModel()
{
QXmlQuery query;
QXmlQuery entries;
QString res;
QDomDocument rhythmdb;
/*
* Try and open the Rhythmbox DB. An API call which tells us where
* the file is would be nice.
*/
QFile db(QDir::homePath() + "/.gnome2/rhythmbox/rhythmdb.xml");
if ( ! db.exists()) {
db.setFileName(QDir::homePath() + "/.local/share/rhythmbox/rhythmdb.xml");
if ( ! db.exists())
return;
}
if (!db.open(QIODevice::ReadOnly | QIODevice::Text))
return;
/*
* Use QXmlQuery to execute and XPath query. Check the version to
* make sure.
*/
query.setFocus(&db);
query.setQuery("rhythmdb[@version='1.6']/entry[@type='song']");
if ( ! query.isValid())
return;
query.evaluateTo(&res);
db.close();
/*
* Parse the result as an XML file. These shennanigans actually
* reduce the load time from a minute to a matter of seconds.
*/
rhythmdb.setContent("" + res + "");
m_entryNodes = rhythmdb.elementsByTagName("entry");
for (int i = 0; i < m_entryNodes.count(); i++) {
QDomNode n = m_entryNodes.at(i);
QString location = n.firstChildElement("location").text();
m_mTracksByLocation[location] = n;
}
qDebug() << rhythmdb.doctype().name();
qDebug() << "RhythmboxTrackModel: m_entryNodes size is" << m_entryNodes.size();
}
In case anyone is wondering, this is my code taken from a recent branch of the Mixxx project, specifically the features_looping branch.
The things I dislike about this solution are:
- Parsing the XML twice
- Concatenating the result with a starting and ending tag.
Problem
How do I run an XPath query in QT? I need to sort out certain tags with specific values in a certain attribute. The QXmlQuery documentation is anything but legible. The schema I'm parsing is the Rhythmbox DB format: ``` <rhythmdb version="1.6"> <entry type="ignore"> <title></title> <genre></genre> <artist></artist> <album></album> <location>file:///mnt/disk/music/Cover.jpg</location> <mountpoint>file:///mnt/disk</mountpoint> <mtime>1222396828</mtime> <date>0</date> <mimetype>application/octet-stream</mimetype> <mb-trackid></mb-trackid> <mb-artistid></mb-artistid> <mb-albumid></mb-albumid> <mb-albumartistid></mb-albumartistid> <mb-artistsortname></mb-artistsortname> </entry> <entry type="song"> <title>Bar</title> <genre>Foobared Music</genre> <artist>Foo</artist> <album>The Great big Bar</album> <track-number>1</track-number> <disc-number>1</disc-number> <duration>208</duration> <file-size>8694159</file-size> <location>file:///media/disk/music/01-Foo_-_Bar.ogg <mountpoint>file:///media/disk <mtime>1216995840</mtime> <first-seen>1250478814</first-seen> <last-seen>1250478814</last-seen> <bitrate>301</bitrate> <date>732677</date> <mimetype>application/x-id3</mimetype> <mb-trackid></mb-trackid> <mb-artistid></mb-artistid> <mb-albumid></mb-albumid> <mb-albumartistid></mb-albumartistid> <mb-artistsortname></mb-artistsortname> </entry> </rhythmdb> ``` This is your basic XML Schema which has a collection of structured entries. My intention was to filter out the entries with the type 'ignore'.