LINUX.ORG.RU

[C++][Qt] Как быстро работать с XML

 ,


0

2

День добрый. До сих пор тут в read-only режиме был, но вот и у меня возникла проблема: надо читать с помощью Qt здоровые и сложные по структуре XML, и моя подсмотренная у одного XML-редактора реализация «читалки» оказалась дико тормозной.
Собственно вот эта функция, от которой все беды:

QDomElement SigmaDCFile::getXmlElement(const QDomNode & domNode, const QString& path, Qt::CaseSensitivity caseSensitivity) const {
    QStringList elementTagNames = path.split('/');
    QDomNodeList domNodeList = domNode.childNodes();
    for(int i = 0; i < domNodeList.count(); i++)
        if(domNodeList.at(i).toElement().tagName().compare(elementTagNames.first(),caseSensitivity) == 0) {
            elementTagNames.takeFirst();
            if(elementTagNames.isEmpty())
                return domNodeList.at(i).toElement();
            else
                return getXmlElement(domNodeList.at(i).toElement(),elementTagNames.join("/"), caseSensitivity);
        }
    return QDomElement();
}
Так-то, она весьма удобна - можно просто обращаться к любому элементу с помощью полного пути, и код загрузки краткий получается. Возможно в данном случае и простой доступ по пути/тегу к элементу получить, и тормозов не словить? как в пословице про рыбку и еще кое-что :) Так-то, структура XML-я фиксированная, но вот новые дочерние элементы таки могут появляться. И напрямую бежать по всему файлу с помощью QDomElement вариант унылый. P.S. Документацию Qt смотрел. Ничего подходящего не обнаружил, благо в XML я нуб.

напрямую бежать по всему файлу с помощью QDomElement вариант унылый

это xml детка, привыкай

//код не смотрел

shty ★★★★★
()
Ответ на: комментарий от shty

Э, а вот так никак нельзя?

m_domElement = getXmlElement(m_rootNode, "/LEVEL1/LEVEL2/LEVEL3/WIDTH", Qt::CaseInsensitive)
Ведь эта функция и приведена в коде, который не был посмотрен :) Еще бы скорости ей.

anarelian
() автор топика
Ответ на: комментарий от anarelian

проблема с xml в том, что у Вас есть список узлов первого уровня, который надо просмотреть и найти первый элемент пути, потом у найденного элемента есть (ну, или может быть) список второго уровня, который снова надо просмотреть, и т.д.

прямо прыгнуть в нужную точку не получится, и это ограничение xml

как вариант можно написать свой кастомный парсер, с требуемой функциональностью

shty ★★★★★
()
Ответ на: комментарий от anonymous

Это которая libxml2, на Си написана? Да не хотелось бы лишнюю зависимость тащить. Ну вряд ли же в Qt настолько плохо парсинг XML реализован.

anarelian
() автор топика
Ответ на: комментарий от anonymous

>libxml всяко быстрее QtXml

ой да ладно. Посоветовал бы тогда RapidXML

annulen ★★★★★
()
Ответ на: комментарий от shty

Структура файла известна, меняться она не будет. Так что где какой уровень находится, и кто в нём живет - я в принципе заранее знаю. Но сколько не пытался велосипедить на QDomElement::nextSibling() и т.п., что-то ужас сплошной выходит, файл больно сложный. Вот говорите - кастомный парсер. Можете раскрыть тему? если пример есть, то и вообще замечательно было бы :)

anarelian
() автор топика
Ответ на: комментарий от schizoid

Вспоминая документацию Qt: SAX грузит файл постепенно, а DOM сразу и целиком. И различие между ними только в «жручести» памяти. Или не так понял я?

anarelian
() автор топика
Ответ на: комментарий от anarelian

«Жручесть» памяти для больших xml-файлов проявляется ещё и в более медленной работе DOM по сравнению с SAX.

schizoid ★★★
()
Ответ на: комментарий от annulen

Помучал Ассистента, нашел пример.

QXmlStreamReader xml;
   ...
   while (!xml.atEnd()) {
         xml.readNext();
         ... // do processing
   }
   if (xml.hasError()) {
         ... // do error handling
   }
Т.е. опять злополучный цикл, который с моими навороченными XML-ми (сразу 4 штуки надо прочесть) в лапшу превратится. Я же надеюсь еще на github потом результат выложить, а там такое вряд ли оценят. Ну если это прямо единственный вариант, то что ж. Спасибо в любом случае.

anarelian
() автор топика
Ответ на: комментарий от anarelian

>Ну если это прямо единственный вариант, то что ж.

Может и не единственный, и не самый красивый, но по крайней мере быстрее и экономичнее к памяти

annulen ★★★★★
()
Ответ на: комментарий от anarelian

>сразу 4 штуки надо прочесть

читай их в разных циклах

annulen ★★★★★
()

Есть альтернативный вариант: сделать из здоровый и сложных нездоровые^Wпростые: выкинуть лишнее, выпрямить структуру. XSLT или XQuery в помощь.

annulen ★★★★★
()
Ответ на: комментарий от annulen

Эхх, значит придётся жертвовать читабельностью. Еще бы кодогенерилка была бы - на вход подаёшь XML с классами, на выходе получаешь уже плюсовый custom parser. Мечты-мечты :)

anarelian
() автор топика
Ответ на: комментарий от annulen

Да там проще и не сделаешь, больно много информации. Вот и думаю, как бы загрузку по разным местам аккуратнее разнести. Функция в пару сотен строк - совсем не дело же. Разве что - два лишних уровня вложенности зачем-то навернули, а мне теперь тащить это ради совместимости. Примерно так: [code] <LVL1> <LVL2> <LVL4> <-- здесь уже полезная информация -> [/code] Оно сильно тормозит работу разве? Что касается XQuery - пытался по википедии вкурить что это, но не очень-то вышло. Аналог SQL для XML?

anarelian
() автор топика
Ответ на: комментарий от anonymous

Не в курсе такой штуки. Но она разве с XML работает?

anarelian
() автор топика
Ответ на: комментарий от anarelian

>Еще бы кодогенерилка была бы - на вход подаёшь XML с классами, на выходе получаешь уже плюсовый custom parser.

Такие есть [напр., 1], хотя и свою (заточенную под задачу) написать не так уж трудно, при этом вовсе не обязательно писать саму генерилку на С++ :)

Примерно так: [code] <LVL1> <LVL2> <LVL4> <-- здесь уже полезная информация -> [/code] Оно сильно тормозит работу разве?

Да нет, но меньшую вложенность парсить проще

Что касается XQuery - пытался по википедии вкурить что это, но не очень-то вышло. Аналог SQL для XML?

Это такой язык для обработки XML и превращения в текст произвольного формата. Хотя, как и XSLT, лучше всего заточен под XML -> XML

[1] http://www.codesynthesis.com/products/xsde/

annulen ★★★★★
()

annulen, reader - XSD/e похоже именно то, что нужно! а я аж кончил и закурил, как пример на главной увидел :) да оно и GPL-ное еще, вообще красота. Правда придётся с XML Schema разобраться, доки покурить, но разве привыкать. Единственная непонятка - как не зависеть от изменений в подэлементах файла, которые могут быть. Оно же скрупулезно 1-в-1 схему реализует, и всё.

anarelian
() автор топика
Ответ на: комментарий от anarelian

>Это которая libxml2, на Си написана?

И это хорошо. Не тормозное Qtшное говно.

Да не хотелось бы лишнюю зависимость тащить.

И давно в Линуксе базовые библиотеки стали лишней зависимостью? Ты бы ещё libc лишней зависимостью назвал.

Ну вряд ли же в Qt настолько плохо парсинг XML реализован.

Ты не поверишь. Более или менее хорошо в Qt реализован только гуй.

terminator
()
Ответ на: комментарий от terminator

>И давно в Линуксе базовые библиотеки стали лишней зависимостью?

И давно это libxml2 стала из части Гнома базовой библиотекой?

annulen ★★★★★
()
Ответ на: комментарий от anarelian

>да оно и GPL-ное еще, вообще красота

ну это кому как)

Правда придётся с XML Schema разобраться, доки покурить, но разве привыкать.

Собственно это меня в XSD и не устроило. Гибкий формат схемой описать практически невозможно, да и саму схему составлять и поддерживать не слишком приятно из-за громоздкости формата.

annulen ★★★★★
()
Ответ на: комментарий от terminator

>>Ну вряд ли же в Qt настолько плохо парсинг XML реализован.

Ты не поверишь.

А в чем, собственно, предъява? Нормальный потоковый некопирующий парсер.

annulen ★★★★★
()
Ответ на: комментарий от annulen

Велосипед. Невелосипедного в Qt только гуй (кстати, очень хороший: написание гуя на Qt — просто сказка), а вот остальное — следствие NIH-синдрома его разработчиков (перекинувшегося и на разработчиков KDE, кстати).

terminator
()
Ответ на: комментарий от annulen

>И давно это libxml2 стала из части Гнома базовой библиотекой?

Это всё равно что сказать: «И давно это libc стала из части GNU базовой библиотекой?»

terminator
()

не пущать больше за комп, господи, откуда такие программисты берутся, стыдно за профессию.
Конечно, DOM парсер будет уныл. Конечно, надо использовать SAX.

Еще бы кодогенерилка была бы - на вход подаёшь XML с классами, на выходе получаешь уже плюсовый custom parser.

внезапно, давно такое есть. альтернатива xml (комментарий)

JFreeM ★★★☆
()
Ответ на: комментарий от terminator

>Велосипед. Невелосипедного в Qt только гуй (кстати, очень хороший: написание гуя на Qt — просто сказка), а вот остальное — следствие NIH-синдрома его разработчиков (перекинувшегося и на разработчиков KDE, кстати).

Вместо технической аргументации балабольство про NIH-синдром. Тогда любой из кучи XML-парсеров, олтличный от libxml2, тоже велосипед, даже expat, который был написан раньше.

annulen ★★★★★
()
Ответ на: комментарий от terminator

>И давно это libc стала из части GNU базовой библиотекой?

Как-то странно сравнивать libc (точнее, glibc, поскольку есть куча альтернатив) с XML-парсером.

Если я пишу под эмбеддед на Qt, для меня libxml2 - это сторонняя бибилотека, которую надо пихать в систему. Если я пишу кросс-платформенное приложение с поддержкой W... и M..., для меня libxml2 это лишняя зависимость, которую нужно собирать и распространять вместе с продуктом.

annulen ★★★★★
()
Ответ на: комментарий от anarelian

Вот говорите - кастомный парсер. Можете раскрыть тему? если пример есть, то и вообще замечательно было бы :)

а что тут раскрывать, данные есть - это исходный xml, парсите его любым движком, да хоть текущим, и перекладываете данные в какую-нибудь подходящую для Вашего случая структуру

рискну предположить, что тут подойдёт какое-нибудь гибридное дерево, наподобие троичного

...

profit!

shty ★★★★★
()
Ответ на: комментарий от annulen

XSLT

кстати, да, но это колдунство, его придётся осваивать :)

shty ★★★★★
()
Ответ на: комментарий от terminator

Кто здесь вообще говорил про КДЕ, кроме тебя? Слив защитан.

annulen ★★★★★
()
Ответ на: комментарий от anarelian

> Структура файла известна, меняться она не будет.

Поубивал бы таких самоуверенных (и ленивых?) программистов.

anonymous
()
Ответ на: комментарий от annulen

Покурил XML Schema - похоже, и мне гибкости не хватит :( рано обрадовался. Так, нужны регулярные выражения в _названиях_ (а не только в значениях) элементов: иначе как я опишу список item_1, item_2, ...

А SAX-парсер что-то неверно работает - его функция characters() возвращает почему-то сам тег, а не его значение.

anarelian
() автор топика
Ответ на: комментарий от JFreeM

Из мухосранских вузов. Я не виноват, что меня ничему там не научили, и стараюсь хоть сейчас наверстать. Это плохо? надо ягу может у подъезда пить?

Ну да ладно. Про SAX - из документации к Qt это было неочевидно, да. Да и сейчас реализовал пробный класс-парсер - оно в characters(QString & data) выводит не значения, как должно (судя по примерам), а теги. ЧЯДНТ-то.

anarelian
() автор топика
Ответ на: комментарий от anarelian

Ан нет, файл кривой оказался. SAX использовать буду я. Всем спасибо! Даже троллям :)

anarelian
() автор топика
Ответ на: комментарий от JFreeM

Ну, в профиле у меня вроде написано, что я только учусь. Могли бы и заглянуть, это ж не код чужой разбирать.

Ну да ладно, хорошо то, что хорошо кончается :) Как-то мне здесь и вовсе посоветовали выйти в окно...

anarelian
() автор топика
Ответ на: комментарий от anarelian

> иначе как я опишу список item_1, item_2, ...

Если N в item_1, item_2, ..., item_N заранее известно, то ручками. Если не известно, ты не должен хотеть имена тэгов с такими номерами. Смотри xsd:sequence

LamerOk ★★★★★
()
Ответ на: комментарий от anarelian

>А SAX-парсер что-то неверно работает

Скорее всего, ты что-то неправильно делаешь, но я все-таки советую не SAX, а StreamReader - может код и громоздко выглядит, но зато прозрачен

annulen ★★★★★
()
Ответ на: комментарий от anonymous

>Поубивал бы таких самоуверенных (и ленивых?) программистов.

Я бы тоже поубивал, но они в другом отделе и пишут серверную часть... :)

annulen ★★★★★
()
Ответ на: комментарий от LamerOk

Оно в отдельном элементе Count. Можно это поле как-то присобачить к имени? Так-то согласен, ни к чему такие сложности в именовании - но формат не мой, я только разместил объявление^W^Wработаю с ним. Кстати, xsd:sequence не подходит - оно же жестко задает порядок тегов, а они могут идти в любом порядке. Более того - могут и новые добавлять в самые нижние уровни :( Как это отследить в схеме, тоже неясно.

anarelian
() автор топика
Ответ на: комментарий от annulen

Да уже разобрался - XML кривой был. На другом значения уже выдает. Глянул сейчас пример с менеджером закладок из Qt - на SimpleReader и StreamReader. Код ужасен что там, что там. В двух словах, если можно - чем StreamReader лучше? ЗЫ: вот теперь я понимаю, что такое ад. Это XML без схемы, непринужденно меняющий состав своих элементов в будущем...

anarelian
() автор топика
Ответ на: комментарий от anarelian

> Как это отследить в схеме, тоже неясно.

Почему не ясно? Ясно - никак. Задача XML схемы - чётко ограничить множество валидных документов. Чётко ограничить неизвестное множество нельзя по определению.

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

Значит туплю, извините. И спасибо за пояснение. Я просто думал, что есть может специальный маркер для обозначения последовательности произвольных элементов - но только в самых нижних уровнях, где уже нужная информация лежит. Т.е. множество не произвольное по сути, структура документа уже определена. Только на нижних уровнях могут дополнительные теги добавляться, и всё.
Кстати, такой вопрос - задавать списки элементов надо же так

<root>
  <item>
    <subitem1>
  <item>
    <subitem2>
  ...
  <item>
     <subitemN>
</root>
а не как у меня
<root>
  <item0>
    <subitem1>
  <item1>
    <subitem2>
  ...
  <itemN>
     <subitemN>
  <count>N
</root>
? Если да, то чую придётся пинать разработчиков этого формата.

anarelian
() автор топика
Ответ на: комментарий от anarelian

> Т.е. множество не произвольное по сути, структура документа уже определена. Только на нижних уровнях могут дополнительные теги добавляться, и всё.

Ты определись. Либо множество не произвольное, либо теги могут добавлятся.

задавать списки элементов надо же так

Либо:

root { prefix_item {subitmes}, itemlist { item {subitem}, item {subitem}}, postfix_item {subitems}}

, либо

root {item1 {subitem1}, item2 {subitem2}, item3{ subitem3_1, subitem3_2}}

LamerOk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.