Как мне выполнить запросы XPath в QT?
Как запустить запрос XPath в QT?
Мне нужно отсортировать определенные теги с конкретными значениями в определенном атрибуте. Документация QXmlQuery совсем не разборчива.
Схема, которую я анализирую, - это формат Rhythmbox DB:
<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>
Это ваша базовая XML-схема, которая имеет коллекцию структурированных записей. Я намеревался отфильтровать записи с типом "игнорировать".
2 ответа
Соответствующая документация находится по адресу: http://qt-project.org/doc/qt-4.8/qxmlquery.html.
Решение, к которому я пришел, состояло в том, чтобы использовать QXmlQuery для генерации XML-файла, а затем снова проанализировать его с помощью 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();
}
Если кому-то интересно, это мой код, взятый из недавней ветки проекта Mixxx, в частности ветки features_looping.
Что мне не нравится в этом решении:
- Разбор XML дважды
- Конкатенация результата с начальным и конечным тегом.
Если это соответствует вашим требованиям разбора, вы можете использовать считыватель на основе SAX вместо DOM. Используя QXmlSimpleReader с вложенным классом QXmlDefaultHandler, вы можете получить доступ к каждому элементу вашего запроса XPath, а также к его атрибутам при сканировании документа. Я думаю, что этот подход будет быстрее, чем основанный на DOM; вам не нужно ничего читать дважды, и это уже встроено в Qt. Вот пример: http://www.digitalfanatics.org/projects/qt_tutorial/chapter09.html разделе "Чтение с использованием SAX".