2009-08-17 5 views
8

Come si esegue una query XPath in QT?Come posso eseguire query XPath in QT?

Ho bisogno di ordinare determinati tag con valori specifici in un determinato attributo. La documentazione di QXmlQuery è tutt'altro che leggibile.

Lo schema che sto analisi è il formato 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> 
 

Questo è il vostro XML Schema di base che ha una collezione di voci strutturati. La mia intenzione era di filtrare le voci con il tipo "ignora".

risposta

11

La documentazione pertinente è il seguente: http://qt-project.org/doc/qt-4.8/qxmlquery.html#running-xpath-expressions.

La soluzione a cui sono arrivato era utilizzare QXmlQuery per generare un file XML e quindi analizzarlo nuovamente utilizzando 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(); 
} 
 

Nel caso in cui qualcuno si sta chiedendo, questo è il mio codice preso da un recente ramo della Mixxx project, in particolare il ramo features_looping.

Le cose che non mi piace di questa soluzione sono:

  • Analisi del XML due volte
  • concatenando il risultato con un inizio e fine tag.
+0

Non è necessario analizzare l'XML due volte; utilizzare semplicemente un diverso overload QXmlQuery :: evaluateTo(). Basta usare il risultato 'QXmlResultItems; query.evaluateTo (& result); ' e quindi scorrere su 'risultato' per ottenere tutti i nodi corrispondenti. Vedere http://doc.trolltech.com/main-snapshot/qxmlresultitems.html –

+1

XMLResultItems, XMLItems o XMLNodeItems non sono adeguati per quanto ho potuto vedere dalla documentazione. Come dice la documentazione: "Poiché QXmlNodeModelIndex è intenzionalmente una classe semplice, non ha funzioni membro per accedere alle proprietà dei nodi." –

+0

Come dice la documentazione: "Poiché QXmlNodeModelIndex è intenzionalmente una classe semplice, non ha funzioni membro per accedere alle proprietà dei nodi." Completamente d'accordo. C'è un modo SEMPLICE per eseguire una richiesta XPath e navigare facilmente attraverso il risultato? Sto iniziando a pensare che la risposta è no! Sto cercando sul web da 2 giorni e non trovo nulla. Penso che userò la Gnome libxml invece di QtXml, ma fa schifo usando g –

-2

Se soddisfa i requisiti di analisi, è possibile utilizzare il lettore basato su SAX anziché uno basato su DOM. Utilizzando QXmlSimpleReader con un QXmlDefaultHandler sottoclassificato, è possibile ottenere l'accesso a ciascun elemento della query XPath nonché i relativi attributi durante la scansione del documento. Penso che questo approccio sarebbe più veloce di uno basato su DOM; non devi leggere nulla due volte ed è già integrato in Qt. C'è un esempio qui: http://www.digitalfanatics.org/projects/qt_tutorial/chapter09.html in "Lettura usando SAX".

+1

Mentre i parser SAX hanno il loro posto, non è così. XPath è una tecnologia basata su DOM. –