crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

> QXmlStreamReader и большое количество уровней
SABROG
  опции профиля:
сообщение 13.7.2009, 14:50
Сообщение #1


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

Спасибо сказали: 229 раз(а)




Репутация:   34  


Решил попробовать класс QXmlStreamReader. Изучив пример streambookmarks я реализовал свой парсер. И вот что мне не понравилось. Можно написать простенький код, который будет сравнивать каждое название ключа на токен isStartElement с нужным нам. Недостаток такого метода - большое количество операций сравнений и падение скорости. Зато очень просто, когда ключи имеют уникальные имена, не нужно контролировать вложенность, родительские отношения. Второй вариант (правильный). На каждый уровень дерева выделяется отдельный метод с while(!atEnd()). Подобное выделение требует создание нового метода для каждого такого уровня. Если глубина дерева в xml'e большая, то можно себе представить какое огромное количество методов получится! Например у меня глубина дерева такая:

tourml/sources/source/packets/packet/packetheader/spo/dates/date


Т.е. 9 методов (на каждый уровень) и в каждом по циклу while(). При этом меня совершенно не интересуют промежуточные уровни, только последние.

Теперь сижу и думаю может сделать какие-нибудь указатели на методы, которые будут вызываться по очереди на одном while. Скажем QQueue/QHash с указателем на метод и строкой сравнения.
---
Только вот на самом деле там даже больше 9и методов получится, т.к. в xml'е еще другие блоки есть, такой например:

tourml/references/tourtypes/tourtype


Сообщение отредактировал SABROG - 13.7.2009, 14:59
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
 
Начать новую тему
Ответов
SABROG
  опции профиля:
сообщение 15.7.2009, 13:16
Сообщение #2


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

Спасибо сказали: 229 раз(а)




Репутация:   34  


Как я и писал выше затык будет в заполнении таблицы. Мы всё-таки дерево парсим, где может быть не один ребенок у одной ветки. Сложно представить как управлять таким автоматом. Я переделал так, мне кажется это золотая середина:

Раскрывающийся текст
bool XmlSpoListParser::read(QIODevice *device)
{
    setDevice(device);

    while (!atEnd()) {
        readNext();

        if (isStartElement()) {
            if (name() == QLatin1String("TourML") && attributes().value(QLatin1String("version")) == QLatin1String("1.0")) {
                readSpoList();
                break;
            } else {
                raiseError(QObject::tr("The file is not an TourML version 1.0 file."));
                break;
            }
        }
    }

    return !error();
}

void XmlSpoListParser::readSpoList()
{
    Q_ASSERT(isStartElement() && name() == QLatin1String("TourML"));

    while (!atEnd()) {
        readNext();

        if (isStartElement()) {
            if (name() ==  QLatin1String("references")) {
                readCountries();
            } else if (name() == QLatin1String("sources")) {
                readTours();
            } else {
                skipSubTree();
            }
        }
}

void XmlSpoListParser::readCountries()
{
    Q_ASSERT(isStartElement() && name() == QLatin1String("references"));

    readNext(); //skip "countries" tag
    readNext(); //skip "Characters" token

    while (!(isEndElement() && name() == QLatin1String("references"))) {
        readNext();
        if (isStartElement()) {
            if (name() == QLatin1String("country")) {
                qDebug() << attributes().value(QLatin1String("nameLat"));
            } else {
                skipSubTree();
            }
        }
    }
}

void XmlSpoListParser::readTours()
{
    Q_ASSERT(isStartElement() && name() == QLatin1String("sources"));

//something like nextTag() in Java, reduce while cycles

    readNext(); //skip "source" tag
    readNext(); //skip "Characters" token
    readNext(); //skip "quotaServices" tag
    readNext(); //skip "Characters" token
    readNext(); //skip "endElement" token
    readNext(); //skip "packets" tag
    readNext(); //skip "Characters" token

    while (!(isEndElement() && name() == QLatin1String("sources"))) {
        readNext();
        if (isStartElement()) {
            if (name() == QLatin1String("packet")) {
                readPacket();
            } else {
                skipSubTree();
            }
        }
    }
}

void XmlSpoListParser::readPacket()
{
    Q_ASSERT(isStartElement() && name() == QLatin1String("packet"));
    readNext(); //skip "packetHeader" tag
    readNext(); //skip "Characters" token

    while (!(isEndElement() && name() == QLatin1String("packet"))) {
        readNext();
        if (isStartElement()) {
            if (name() == QLatin1String("tour"))
                qDebug() << attributes().value(QLatin1String("name"));
            else if (name() == QLatin1String("spo"))
                qDebug() << attributes().value(QLatin1String("issue"));
            else if (name() == QLatin1String("spoInfo")) {
                readNext(); //move to "priceQuantity" tag
                readNext(); //skip "Characters" token
                qDebug() << readElementText();
            } else
                skipSubTree();
        }
    }
}

void XmlSpoListParser::skipSubTree()
{
    Q_ASSERT(isStartElement());

    while (!atEnd()) {
        readNext();
        if (isEndElement())
            break;
        if (isStartElement())
            skipSubTree();
    }
}


Кстати как я не изгалялся над алгоритмом время парсинга почему-то всегда константно: 297ms. Если использую qDebug() для вывода в консоль, то время парсинга увеличивается до 1048ms. Правда у этого варианта тоже есть существенный недостаток, чтобы использовать стриминг надо проверять на ошибку после каждого readNext() иначе есть шанс прочитать несуществующие аттрибуты или тектовые элементы.

Сообщение отредактировал SABROG - 15.7.2009, 14:54
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Сообщений в этой теме
- SABROG   QXmlStreamReader и большое количество уровней   13.7.2009, 14:50
- - ViGOur   Код в студию, можно занятся оптимизаторством и уни...   13.7.2009, 15:56
|- - SABROG   Цитата(ViGOur @ 13.7.2009, 16:56) Код в с...   13.7.2009, 17:45
- - ViGOur   Жесть! А почему нельзя сделать рекурсию с соз...   13.7.2009, 19:29
- - SABROG   Цитата(ViGOur @ 13.7.2009, 20:29) А почем...   13.7.2009, 20:28
- - SABROG   Да уж, что-то не очень получается. Если делать рек...   14.7.2009, 14:25
- - SABROG   В общем посмотрел я десяток примеров использования...   14.7.2009, 22:40
- - ViGOur   Ты немного не понял, рекурсия c примерно таким усл...   15.7.2009, 10:32
- - SABROG   Да оно всё это понятно, я тоже об этом говорю. Сам...   15.7.2009, 11:14
- - ViGOur   Так в том то и дело, что в твоем случае как я поня...   15.7.2009, 12:24
- - Tonal   То, что тут пытаетесь изобразить, называется конеч...   15.7.2009, 12:38
- - SABROG   Как я и писал выше затык будет в заполнении таблиц...   15.7.2009, 13:16
- - SABROG   Такой вопрос насчет QXmlStreamReader::PrematureEnd...   15.7.2009, 21:35
- - SABROG   Нашел забавную статью про StAX, пример рассматрива...   22.7.2009, 15:33
- - SABROG   Сегодня заметил статью в блоге на QtSoftware и о т...   24.7.2009, 13:27
- - Litkevich Yuriy   Цитата(SABROG @ 24.7.2009, 17:27) я немно...   24.7.2009, 13:39
- - SABROG   В общем я немного заморочился на эту тему и напи...   29.8.2009, 14:40


Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 29.3.2024, 8:33