Russian Qt Forum

Qt => XML => Тема начата: White Owl от Декабрь 09, 2009, 22:06



Название: вытащить значение аттрибута средствами QXmlQuery
Отправлено: White Owl от Декабрь 09, 2009, 22:06
Имеется xml вида:
<root>
   <group>
      <item key="aaa" value="bbb"/>
      <item key="ccc" value="ddd"/>
      <item key="eee" value="fff"/>
   </group>
</root>

Надо узнать значение аттрибута value если аттрибут key="ccc".
Сделал так:
Код:
    QXmlQuery xmlQuery;
    xmlQuery.setQuery("doc('my.xml')/root/group/item[@key=\"ccc\"]");
    QString sl;
    if(!xmlQuery.evaluateTo(&sl)) qDebug() << "parse error\n";
    qDebug() <<sl;
получаю полностью всю ноду:
<item key="ccc" value="ddd"/>

А дальше как? Что надо дописать запрос чтобы оно выдало только значение аттрибута value?


Название: Re: вытащить значение аттрибута средствами QXmlQuery
Отправлено: ildar от Декабрь 21, 2009, 10:28
Код:
xmlQuery.setQuery("doc('my.xml')/root/group/item[@key=\"ccc\"]/@value");

?


Название: Re: вытащить значение аттрибута средствами QXmlQuery
Отправлено: White Owl от Декабрь 22, 2009, 18:28
Nope... не работает. Текст ошибки:

"<html xmlns='http://www.w3.org/1999/xhtml/'><body><p>Attribute <span class='XQuery-keyword'>value</span> can't be serialized because it appears at the top level.</p></body></html>"


Играюсь вот с этим:
main.cpp
Код:
#include <QtCore>
#include <QtXmlPatterns>

class MessageHandler : public QAbstractMessageHandler {
    public:
        MessageHandler() : QAbstractMessageHandler(0) { }

        QString statusMessage() const { return m_description; }

        int line() const { return m_sourceLocation.line(); }

        int column() const { return m_sourceLocation.column(); }

    protected:
        virtual void handleMessage(QtMsgType type, const QString &description,
                                   const QUrl &identifier, const QSourceLocation &sourceLocation) {
            Q_UNUSED(type);
            Q_UNUSED(identifier);

            m_messageType = type;
            m_description = description;
            m_sourceLocation = sourceLocation;
        }

    private:
        QtMsgType m_messageType;
        QString m_description;
        QSourceLocation m_sourceLocation;
};

int main(int argc, char **argv) {
    QCoreApplication app(argc, argv);

    QXmlQuery xmlQuery;
    MessageHandler messageHandler;
    xmlQuery.setMessageHandler(&messageHandler);

    xmlQuery.setQuery("doc('my.xml')/root/group/item[@key=\"ccc\"]/@value");

    QString sl;
    if(!xmlQuery.evaluateTo(&sl)) {
        qDebug() << "error at line " << messageHandler.line() << ":" << messageHandler.column() <<
                endl << messageHandler.statusMessage() << endl;
    } else {
        qDebug() <<sl;
    }

    return 0;
}

XmlQueryTest.pro
Код:
DESTDIR = ./
CONFIG  += console release
QT      += xmlpatterns
QT      -= gui
SOURCES  = main.cpp


Название: Re: вытащить значение аттрибута средствами QXmlQuery
Отправлено: Marat(Qt) от Январь 07, 2010, 01:38
Используй evaluateTo ( QAbstractXmlReceiver * ) const : bool
и void QAbstractXmlReceiver::attribute ( const QXmlName & name, const QStringRef & value )   [pure virtual]


Название: Re: вытащить значение аттрибута средствами QXmlQuery
Отправлено: ilot от Январь 07, 2010, 08:12
Для небольших документов можно делать так:
Код:
QDomDocument domDoc;
QFile file(m_file);//имя xml-файла
QString attrVal;
if(file.open(QIODevice::ReadOnly)){
if(domDoc.setContent(&file)){
QDomElement root = domDoc.documentElement();//возвращает корневой элемент документа
QDomElement el = root.firstChildElement(m_tagName);
while(!el.isNull())
{
if(el.attribute("key") == "ccc"){
attrVal = el.attribute("value");
break;
}
el = el.nextSiblingElement(m_tagName);
}
}
file.close();
}


Название: Re: вытащить значение аттрибута средствами QXmlQuery
Отправлено: White Owl от Январь 07, 2010, 20:48
Используй evaluateTo ( QAbstractXmlReceiver * ) const : bool
и void QAbstractXmlReceiver::attribute ( const QXmlName & name, const QStringRef & value )   [pure virtual]
Не понял.
Это предполагается создавать дополнительный класс??? Чтобы узнать значение всего одного аттрибута целый класс делать?


Название: Re: вытащить значение аттрибута средствами QXmlQuery
Отправлено: Marat(Qt) от Январь 08, 2010, 02:44
Используй evaluateTo ( QAbstractXmlReceiver * ) const : bool
и void QAbstractXmlReceiver::attribute ( const QXmlName & name, const QStringRef & value )   [pure virtual]
Не понял.
Это предполагается создавать дополнительный класс??? Чтобы узнать значение всего одного аттрибута целый класс делать?
Зачем же целый класс? Достаточно один объект класса создать.
Можете долго рассуждать на эту тему, если вам неохота создавать новый объект ради этого дела, то режте строку руками, и совет, постарайтесь ради того чтобы узнать всего один аттрибут не создавать объект типа QString, он ведь тоже много места занимает в оперативной то памяти....


Название: Re: вытащить значение аттрибута средствами QXmlQuery
Отправлено: White Owl от Январь 08, 2010, 22:01
Зачем же целый класс? Достаточно один объект класса создать.
Один объект какого класса, простите? QAbstractXmlReceiver? Так он абстрактный, нельзя объекты из него создавать, от него только наследовать можно.
Короче говоря, показывай пример решающий задачу с использованием QAbstractXmlReceiver. Если он получится короче семи строк кода я обязательно перейду на него.
А пока я вижу только два пути вытаскивания значения одного-единственного аттрибута из большого xml файла - играться с DOM (полтора десятка строк кода) или вытаскивать текст ноды через QXmlQuery и потом парсить этот текст через регулярки (семь строк кода). Ни один из способов я не считаю элегантным. Первый предназначен все же для обработки DOM документов а второй просто странный.


Название: Re: вытащить значение аттрибута средствами QXmlQuery
Отправлено: Marat(Qt) от Январь 08, 2010, 22:36
Вообще-то у него уже есть наследник, читай Assistant.


Название: Re: вытащить значение аттрибута средствами QXmlQuery
Отправлено: White Owl от Январь 11, 2010, 22:22
Вообще-то у него уже есть наследник, читай Assistant.
Ага, есть, QXmlSerializer называется. А теперь ты сам открой Assistant и почитай описание этого самого QXmlSerializer.


Название: Re: вытащить значение аттрибута средствами QXmlQuery
Отправлено: Marat(Qt) от Январь 12, 2010, 00:50
Я почитал, там и с Abstract'ом та же ситуация, QAbstractXmlReceiver::attribute - это, как оказалось, далеко не то что нужно в этой ситуации.
по сути вот это рабочий код(в смысле запрос синтаксически правильный):
xmlQuery.setQuery("doc('my.xml')/root/group/item[@key=\"ccc\"]/@value");
но он ничего не дает, ни при каких evaluate, а должен бы. Атрибут - это не atomicValue, я не вижу способов его достать, только парсить regexp'ом.


Название: Re: вытащить значение аттрибута средствами QXmlQuery
Отправлено: ilot от Январь 12, 2010, 04:36
А пока я вижу только два пути вытаскивания значения одного-единственного аттрибута из большого xml файла - играться с DOM (полтора десятка строк кода) или вытаскивать текст ноды через QXmlQuery и потом парсить этот текст через регулярки (семь строк кода). Ни один из способов я не считаю элегантным. Первый предназначен все же для обработки DOM документов а второй просто странный.
Приведенные мной полтора десятка строк кода отлично записываются в виде функции. Вызов в клиентском коде будет выглядеть немногословно. Например:
Код:
QString attrValue = getAttr(fileName, tagName, attrName);
Я показал лишь идею, а как вы приспособите ее к своей конкретной задаче, элегантно или нет, зависит от вас. Единственный случай, когда данная техника неприменима - это большие xml-документы, поскольку для построения dom-структуры необходимо загрузить все данные в оперативную память. Но для таких случаев есть SAX.

Пока есть два вопроса:
1. Какой размер xml-файлов?
2. Как часто в процессе работы приложения приходится к ним обращаться?


Название: Re: вытащить значение аттрибута средствами QXmlQuery
Отправлено: White Owl от Январь 12, 2010, 19:45
Я показал лишь идею, а как вы приспособите ее к своей конкретной задаче, элегантно или нет, зависит от вас.
Ну решение через DOM я и сам знал и использовал. Хотелось просто сократить количество кода. Даже если обернуть чтение xml в DOM в виде функции и в реальном коде вызывать эту функцию, то все равно прийдется писать эту самую функцию. Qt'шный девиз "code less create more" уже не выполняется...

Единственный случай, когда данная техника неприменима - это большие xml-документы, поскольку для построения dom-структуры необходимо загрузить все данные в оперативную память. Но для таких случаев есть SAX.
Кому нужен SAX если есть expat?


Название: Re: вытащить значение аттрибута средствами QXmlQuery
Отправлено: SABROG от Апрель 29, 2010, 00:24
Знаю, что топик старый, но в качестве пополнения базы знаний приведу решение:

Код
C++ (Qt)
// var 1
xmlQuery.setQuery("string(doc('my.xml')/root/group/item[@key=\"ccc\"]/@value)");
 
// var 2
xmlQuery.setQuery("doc('my.xml')/root/group/item[@key=\"ccc\"]/@value cast as xs:string");
 
// var 3
xmlQuery.setQuery("doc('my.xml')/root/group/item[@key=\"ccc\"]/@value/string()");
 

Ноги растут из двух этих методов:

bool QXmlQuery::evaluateTo ( QString * output ) const
bool QXmlQuery::evaluateTo ( QStringList * target ) const

Они требуют, чтобы возвращаемые данные были в строковом представлении. XPath,XQuery - типизированы.

Функции типа name(), upper-case(), replace() и некоторые другие не требуют преобразования к строковому типу, так как они и так возвращают результат в виде строки (xs:string). Поэтому такой запрос вполне нормально работает:

Код
C++ (Qt)
xmlQuery.setQuery("doc('my.xml')/root/group/item[@key=\"ccc\"]/@value/name()");