QXmlStreamReader и большое количество уровней |
Здравствуйте, гость ( Вход | Регистрация )
QXmlStreamReader и большое количество уровней |
SABROG |
13.7.2009, 14:50
Сообщение
#1
|
Профессионал Группа: Участник Сообщений: 1207 Регистрация: 8.12.2008 Из: Russia, Moscow Пользователь №: 446 Спасибо сказали: 229 раз(а) Репутация: 34 |
Решил попробовать класс QXmlStreamReader. Изучив пример streambookmarks я реализовал свой парсер. И вот что мне не понравилось. Можно написать простенький код, который будет сравнивать каждое название ключа на токен isStartElement с нужным нам. Недостаток такого метода - большое количество операций сравнений и падение скорости. Зато очень просто, когда ключи имеют уникальные имена, не нужно контролировать вложенность, родительские отношения. Второй вариант (правильный). На каждый уровень дерева выделяется отдельный метод с while(!atEnd()). Подобное выделение требует создание нового метода для каждого такого уровня. Если глубина дерева в xml'e большая, то можно себе представить какое огромное количество методов получится! Например у меня глубина дерева такая:
Т.е. 9 методов (на каждый уровень) и в каждом по циклу while(). При этом меня совершенно не интересуют промежуточные уровни, только последние. Теперь сижу и думаю может сделать какие-нибудь указатели на методы, которые будут вызываться по очереди на одном while. Скажем QQueue/QHash с указателем на метод и строкой сравнения. --- Только вот на самом деле там даже больше 9и методов получится, т.к. в xml'е еще другие блоки есть, такой например:
Сообщение отредактировал SABROG - 13.7.2009, 14:59 |
|
|
SABROG |
29.8.2009, 14:40
Сообщение
#2
|
Профессионал Группа: Участник Сообщений: 1207 Регистрация: 8.12.2008 Из: Russia, Moscow Пользователь №: 446 Спасибо сказали: 229 раз(а) Репутация: 34 |
xmlstreamreaderhelper.zip ( 2,43 килобайт )
Кол-во скачиваний: 333
В общем я немного заморочился на эту тему и написал класс, который назвал по-страшному - xmlstreamreaderhelper Несмотря на то, что понять как он работает не просто я постараюсь все же объяснить суть. Все построено на полиморфизме, чтобы избежать дублирование кода. Есть 2 класса:
Класс AbstractTagProcessor наследует класс AbstractTagImplementator и определяет в себе ряд методов для работы с тэгами xml'я. В то время как класс AbstractTagImplementator определяет общий функционал парсера. Если разбирать мой xml из прошлых постов, то его парсинг теперь выглядит так: //определяем в заголовке набор классов, каждый из которых представление необходимых тегов //.h
В этих классах переопределяются так называемые эвенты базовых классов. Всего 3 эвента: beforeEvent(), event(), afterEvent(). В зависимости от сложности парсера переопределяются нужные. В простом случае нужен только beforeEvent(), а вот если нужно будет перебрать все существующие теги или обработать неизвестные, или просто хочется реализовать свой функционал иначе, то надо переопределять метод event(). //реализация классов тегов //.cpp
//Подготовка и вызов парсера //.cpp
Т.е. открываем файл, создаем объект QXmlStreamReader, которому и передаем device (file). Затем создается родительский объект TourML, и по аналогии с QObject'ами тэги-классы выстраиваются в дерево. Потом на корневом теге вызывается метод parse(), который уже проходит по всему дереву детей. Если в процессе парсинга любого тэга xml прервется, при передаче по сокету например, то запускается локальный QEventLoop и ожидает новые данные с устройства. Если они приходят, то парсинг продолжается дальше. Я пробовал генерировать бесконечный поток xml'я по сокету, парсер работает не прерываясь. Имена, которые передаются в конструкторы объектов - реальные названия тегов в xml'е чувствительные к регистру. Еще вот этот код прокомментирую:
В этом случае тэг "references" является всего-лишь "чекпоинтом", нам тег не нужен сам по себе, но мы должны указать короткую дорогу парсеру, чтобы он мог найти тег "country", поэтому нам нет необходимости наследоваться от класса AbstractTagImplementator и мы используем его базовый функционал, которого достаточно. С другой стороны мы могли бы отказаться от этого чекпоинта и парсер бы все равно нашел нужный тег, однако в разных ситуациях это может замедлить скорость парсинга, т.к. заставит парсер сравнивать имена ключей, которые мы могли бы отмести заранее. А в случае, когда у разных подветок имеются ключи с одинаковым названием это может привести к путанице и невозможности узнать какой из подветок принадлежит тег, чтобы соотнести его. Как по мне, так это выглядит более правильно, чем мой первоначальный вариант: Раскрывающийся текст
К тому же замеры скорости не показали каких либо отличительных различий. Классы на C++ я проектирую впервые поэтому был бы рад узнать где я сделал что-то не так и как этом можно улучшить. Есть мысль написать кодо-генератор для парсера, где можно было бы загрузить дерево xml'я и проставляя галочки выбрать путь для парсера. Выкладываю для критики и дополнений исходники. xmlstreamreaderhelper.zip ( 2,43 килобайт ) Кол-во скачиваний: 333 |
|
|
Текстовая версия | Сейчас: 30.12.2024, 19:25 |