LINUX.ORG.RU

Затупил. DOM в Qt. Не могу рекурсивно перебрать QDomElement

 , ,


0

1

У меня в памяти есть QDomDocument. Его нужно сохранить на диск. Перед сохранением надо атрибуты некоторых элементов изменить (расшифровать). Элементы вложены, необходима рекурсия. DOM-элементы должны меняться (менять свои атрибуты) внутри рекурсии.

Примерный код такой:

void KnowTreeModel::saveDecryptDoc(QDomDocument &doc)
{
  decrypt(doc);

  // Запись DOM данных в файл
  QFile wfile("file.xml");
  QTextStream out(&wfile);
  out.setCodec("UTF-8");
  out << doc.toString();
}


void KnowTreeModel::decrypt(QDomDocument &doc)
{
  QDomElement contentElement=doc.documentElement().firstChildElement("content").firstChildElement("node");

  decryptRecurse(contentElement);

  return;
}


void KnowTreeModel::decryptRecurse(QDomElement &element)
{
  // Расшифровка атрибутов
  element.setAttribute("cryptData", decryptMyData(element.attribute("cryptData") ));

  // Рекурсивный вызов дочерних элементов
  QDomNodeList childList=element.childNodes();
  for(int i=0; i<childList.count(); i++) // для QDomNodeList цикл foreach не работает
    if(childList.at(i).isElement())
      decryptRecurse(childList.at(i).toElement()); // <!-- Что тут надо написать ???
}


Проблема в том, что рекурсивная функция должна работать через QDomElement (долго объяснять почему, проект большой). А я не могу понять, как у QDomElement получить дочерние QDomElement.

У QDomElement есть только возможность получить QDomNodeList, но тип у полученных элементов - QDomNode.

А у этого QDomNode невозможно получить указатель на QDomElement, можно только получить новый QDomElement через метод toElement().

(Блин, вообще-то мне нужна ссылка на QDomElement, но я уже сломал мосг).

В общем, вопрос в следующем: как у QDomElement перебрать дочерние QDomElement и что-нибудь в них изменить?

★★★★★

toElement() возвращает не новый QDomElement, а существующий, так как QDomNode использует explicitly shared подход. Там внутрях обычный каст происходит.

Поэтому никакого копирования не будет. Из накладных расходов - только изменение счетчика ссылок.

PS: вообще QDomDocument уныл и поэтому объявлен устаревшим.

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

Для манипуляций - ничего.

Для чтения/записи - QXmlStreamReader/QXmlStreamWriter.

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

toElement() возвращает не новый QDomElement, а существующий, так как QDomNode использует explicitly shared подход. Там внутрях обычный каст происходит. Поэтому никакого копирования не будет. Из накладных расходов - только изменение счетчика ссылок.

Какая разница, что внутри. Мне же нужно менять полученный элемент. А конструкция

childList.at(i).toElement()

возвращает не сам элемент, связанный с QDomNode, а копию его (пускай внутри это и explicitly shared). И если я поменяю копию, то изменения в элементе, связанным с QDomNode, не произойдут.

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

pugixml парсит намного быстрее и с ним можно модифицировать дерево

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

И если я поменяю копию, то изменения в элементе, связанным с QDomNode, не произойдут.

Не путай explicit sharing с implicit.

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

Смотри. Ты пишешь что QDomNode - это explicitly shared. То есть, его «копия» будет работать с данными оригинала. Это только половина дела.

Вопрос в том, что мы получим в результате команды

domNodeInstance.toElement()

Мы получим новый QDomElement, или explicitly shared - копию объекта класса QDomElement?

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

То есть, вот я читаю документацию на toElement():

Converts a QDomNode into a QDomElement. If the node is not an element the returned object will be null.

Ничего не говорится по то, что мы получаем в качестве данных - explicitly shared копию QDomElement, связанный с QDomNode, или новый QDomElement.

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

Не путай explicit sharing с implicit.

Мы выяснили, что QDomNode - это explicit.

Но нам то нужно работать с QDomElement. Документация не проливает свет на тип шаринга данных.

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

Не могу запустить, компиляция не идет.

У меня есть два вызова рекурсивного метода: стартовый и внутри самого рекурсивного метода. (Буду показывать на реальном коде).

На вызове стартового метода компилятор не ругается. Стартовый вызов выглядит так:

  QDomElement contentRootNode=doc.documentElement().firstChildElement("content").firstChildElement("node");

  exportRelatedDataAndDecryptIfNeedRecurse(contentRootNode, exportDir);


А рекурсивный вызов выглядит так:

void KnowTreeModel::exportRelatedDataAndDecryptIfNeedRecurse(QDomElement &element, QString exportDir)
{
  ...

  // Рекурсивный вызов дочерних элементов
  QDomNodeList childList=element.childNodes();
  for(int i=0; i<childList.count(); i++)
    if(childList.at(i).isElement())
      exportRelatedDataAndDecryptIfNeedRecurse( childList.at(i).toElement(), exportDir);
}


И он не компилится. Имеем такую ошибку:

KnowTreeModel.cpp: In member function 'void KnowTreeModel::exportRelatedDataAndDecryptIfNeedRecurse(QDomElement&, QString)':
KnowTreeModel.cpp:403:87: error: no matching function for call to 'KnowTreeModel::exportRelatedDataAndDecryptIfNeedRecurse(QDomElement, QString&)'
       exportRelatedDataAndDecryptIfNeedRecurse( childList.at(i).toElement(), exportDir);
                                                                                       ^
KnowTreeModel.cpp:403:87: note: candidate is:
KnowTreeModel.cpp:344:6: note: void KnowTreeModel::exportRelatedDataAndDecryptIfNeedRecurse(QDomElement&, QString)
 void KnowTreeModel::exportRelatedDataAndDecryptIfNeedRecurse(QDomElement &element, QString exportDir)
      ^
KnowTreeModel.cpp:344:6: note:   no known conversion for argument 1 from 'QDomElement' to 'QDomElement&'



Я уже мозг сломал, почему в первом случае QDomElement спокойно передается по ссылке, а во втором случае - нет.

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

Ссылке нужно имя. Мля, какой же gcc ксотноязычный.

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

Ну так все верно. Вы же не ссылку передаёте, а объект.
Для нормальной разработки есть clang.

А что, в силанге можно вызвать функцию с аргументом типа ссылка без предварительного создания переменной?

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

Нет, зато он может доступно объяснить в чем ошибка, в отличии от.

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