2009-08-17 15 views
8

¿Cómo ejecuto una consulta XPath en QT?¿Cómo ejecuto consultas XPath en QT?

Necesito clasificar ciertas etiquetas con valores específicos en cierto atributo. La documentación de QXmlQuery no es legible.

El esquema que estoy de análisis es el 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> 
 

Ésta es su esquema XML básico que tiene una colección de entradas estructuradas. Mi intención era filtrar las entradas con el tipo 'ignorar'.

Respuesta

11

La documentación pertinente se encuentra en: http://qt-project.org/doc/qt-4.8/qxmlquery.html#running-xpath-expressions.

La solución que encontré fue usar QXmlQuery para generar un archivo XML y luego analizarlo de nuevo usando 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(); 
} 
 

En caso de que alguien se lo pregunta, este es mi código tomado de una rama reciente de la Mixxx project, específicamente la rama features_looping.

Las cosas no me gusta de esta solución son:

  • análisis del XML dos veces
  • concatenando el resultado con una etiqueta de inicio y finalización.
+0

No es necesario analizar el XML dos veces; simplemente use una sobrecarga de QXmlQuery :: evaluateTo() diferente. Simplemente use el resultado 'QXmlResultItems; query.evaluateTo (& result); ' y luego iterar sobre 'resultado' para obtener todos los nodos coincidentes. Ver http://doc.trolltech.com/main-snapshot/qxmlresultitems.html –

+1

XMLResultItems, XMLItems o XMLNodeItems no son adecuados por lo que pude ver en la documentación. Como dice la documentación: "Debido a que QXmlNodeModelIndex es intencionalmente una clase simple, no tiene funciones miembro para acceder a las propiedades de los nodos". –

+0

Como dice la documentación: "Debido a que QXmlNodeModelIndex es intencionalmente una clase simple, no tiene funciones de miembro para acceder a las propiedades de los nodos". Totalmente de acuerdo. ¿Existe alguna forma SIMPLE de ejecutar una solicitud XPath y navegar fácilmente por el resultado? ¡Estoy empezando a pensar que la respuesta es no! Estoy buscando en la web durante 2 días y no encuentro nada. Creo que usaré el libnml de Gnome en lugar de QtXml, pero apesta usando g –

-2

Si se ajusta a sus requisitos de análisis, puede utilizar el lector basado en SAX en lugar de uno basado en DOM. Usando QXmlSimpleReader con QXmlDefaultHandler subclasificado, puede obtener acceso a cada elemento de su consulta XPath, así como a sus atributos a medida que se escanea el documento. Creo que este enfoque sería más rápido que uno basado en DOM; no tiene que leer nada dos veces y ya está integrado en Qt. Aquí hay un ejemplo: http://www.digitalfanatics.org/projects/qt_tutorial/chapter09.html en "Lectura con SAX".

+1

Si bien los analizadores de SAX sí tienen su lugar, no es así. XPath es una tecnología que se basa en DOM. –

Cuestiones relacionadas