Russian Qt Forum
Ноябрь 22, 2024, 21:15 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: вытащить значение аттрибута средствами QXmlQuery  (Прочитано 18878 раз)
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?
Записан
ildar
Гость
« Ответ #1 : Декабрь 21, 2009, 10:28 »

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

?
Записан
White Owl
Гость
« Ответ #2 : Декабрь 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
Записан
Marat(Qt)
Гость
« Ответ #3 : Январь 07, 2010, 01:38 »

Используй evaluateTo ( QAbstractXmlReceiver * ) const : bool
и void QAbstractXmlReceiver::attribute ( const QXmlName & name, const QStringRef & value )   [pure virtual]
Записан
ilot
Гость
« Ответ #4 : Январь 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();
}
Записан
White Owl
Гость
« Ответ #5 : Январь 07, 2010, 20:48 »

Используй evaluateTo ( QAbstractXmlReceiver * ) const : bool
и void QAbstractXmlReceiver::attribute ( const QXmlName & name, const QStringRef & value )   [pure virtual]
Не понял.
Это предполагается создавать дополнительный класс??? Чтобы узнать значение всего одного аттрибута целый класс делать?
Записан
Marat(Qt)
Гость
« Ответ #6 : Январь 08, 2010, 02:44 »

Используй evaluateTo ( QAbstractXmlReceiver * ) const : bool
и void QAbstractXmlReceiver::attribute ( const QXmlName & name, const QStringRef & value )   [pure virtual]
Не понял.
Это предполагается создавать дополнительный класс??? Чтобы узнать значение всего одного аттрибута целый класс делать?
Зачем же целый класс? Достаточно один объект класса создать.
Можете долго рассуждать на эту тему, если вам неохота создавать новый объект ради этого дела, то режте строку руками, и совет, постарайтесь ради того чтобы узнать всего один аттрибут не создавать объект типа QString, он ведь тоже много места занимает в оперативной то памяти....
Записан
White Owl
Гость
« Ответ #7 : Январь 08, 2010, 22:01 »

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

Вообще-то у него уже есть наследник, читай Assistant.
Записан
White Owl
Гость
« Ответ #9 : Январь 11, 2010, 22:22 »

Вообще-то у него уже есть наследник, читай Assistant.
Ага, есть, QXmlSerializer называется. А теперь ты сам открой Assistant и почитай описание этого самого QXmlSerializer.
Записан
Marat(Qt)
Гость
« Ответ #10 : Январь 12, 2010, 00:50 »

Я почитал, там и с Abstract'ом та же ситуация, QAbstractXmlReceiver::attribute - это, как оказалось, далеко не то что нужно в этой ситуации.
по сути вот это рабочий код(в смысле запрос синтаксически правильный):
xmlQuery.setQuery("doc('my.xml')/root/group/item[@key=\"ccc\"]/@value");
но он ничего не дает, ни при каких evaluate, а должен бы. Атрибут - это не atomicValue, я не вижу способов его достать, только парсить regexp'ом.
Записан
ilot
Гость
« Ответ #11 : Январь 12, 2010, 04:36 »

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

Пока есть два вопроса:
1. Какой размер xml-файлов?
2. Как часто в процессе работы приложения приходится к ним обращаться?
Записан
White Owl
Гость
« Ответ #12 : Январь 12, 2010, 19:45 »

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

Единственный случай, когда данная техника неприменима - это большие xml-документы, поскольку для построения dom-структуры необходимо загрузить все данные в оперативную память. Но для таких случаев есть SAX.
Кому нужен SAX если есть expat?
Записан
SABROG
Гость
« Ответ #13 : Апрель 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()");
 
« Последнее редактирование: Апрель 29, 2010, 00:34 от SABROG » Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.286 секунд. Запросов: 21.