Intruder
Sept. 4, 2019, 2:52 a.m.

Как оптимизировать код и вызывать рекурсивно?

Всем доброго времени суток.
У меня есть задача просмотреть все теги в xml-файле и остановиться на нужном, как только он будет найден, т.е. вернуть объект QDomElement, чтобы дальше с ним работать. Я данную задачу решаю в лоб (тут пока простой вывод названия тегов). Т.е., так как я знаю какова вложенность тегов, то я просто выполняю следующий код:

  1. QDomElement docElem = doc.documentElement();
  2. QDomNode n1 = docElem.firstChild();
  3. while(!n1.isNull()){
  4. QDomElement e1 = n1.toElement(); // try to convert the node to an element.
  5. if(!e1.isNull()){
  6. qDebug() << qPrintable(e1.tagName()); // the node really is an element.
  7. if(e1.hasChildNodes())
  8. {
  9. QDomNode n2 = e1.firstChild();
  10. while(!n2.isNull()){
  11. QDomElement e2 = n2.toElement();
  12. if(!e2.isNull()){
  13. qDebug() << qPrintable(" " + e2.tagName());
  14. if(e2.hasChildNodes()){
  15. QDomNode n3 = e2.firstChild();
  16. while (!n3.isNull()) {
  17. QDomElement e3 = n3.toElement();
  18. qDebug() << qPrintable(" " + e3.tagName());
  19. if(e3.hasChildNodes()){
  20. QDomNode n4 = e3.firstChild();
  21. while (!n4.isNull()){
  22. QDomElement e4 = n4.toElement();
  23. qDebug() << qPrintable(" " + e4.tagName());
  24. if(e4.hasChildNodes()){
  25. QDomNode n5 = e4.firstChild();
  26. while (!n5.isNull()) {
  27. QDomElement e5 = n5.toElement();
  28. qDebug() << qPrintable(" " + e5.tagName());
  29. if(e5.hasChildNodes()){
  30. QDomNode n6 = e5.firstChild();
  31. while (!n6.isNull()) {
  32. QDomElement e6 = n6.toElement();
  33. qDebug() << qPrintable(" " + e6.tagName());
  34. n6 = n6.nextSibling();
  35. }
  36. }
  37. n5 = n5.nextSibling();
  38. }
  39. }
  40. n4 = n4.nextSibling();
  41. }
  42. }
  43. n3 = n3.nextSibling();
  44. }
  45. }
  46. }
  47. n2 = n2.nextSibling();
  48. }
  49. }
  50. }
  51. n1 = n1.nextSibling();
  52. }

Вроде бы ничего сложного нет, но это уж слишком грамоздко. Хотелось бы использовать рекурсию. Но логически я понимаю что нужно делать, но как это реализуется на практике для меня темный лес. Перечитал много примеров и с числами Фибоначи, и с решением факториала. Но переложить на свой пример что-то не получается. Нужно ли вводить глобальные переменные, необходимые для посчета итераций? И тому подобное?

3

Do you like it? Share on social networks!

3
IscanderChe
  • Sept. 4, 2019, 12:17 p.m.

Вот пример, как это сделано у меня.

В основном теле делается вызов функции readReport , а потом он же делается внутри функции рекурсивно, до конца дерева документа. Безо всяких глобальных переменных.

Основное тело

  1. QDomDocument domDoc;
  2. QFile file(pathToFile);
  3.  
  4. if(file.open(QIODevice::ReadOnly))
  5. {
  6. if(domDoc.setContent(&file))
  7. {
  8. QDomElement domElement = domDoc.documentElement();
  9. readReport(domElement);
  10. }
  11. file.close();
  12. }
  13. else
  14. {
  15. qDebug() << "Error reading file!";
  16. exit (1);
  17. }

readReport

  1. readReport(const QDomNode& node)
  2. {
  3. QDomNode domNode = node.firstChild();
  4. while(!domNode.isNull())
  5. {
  6. if(domNode.isElement())
  7. {
  8. QDomElement domElement = domNode.toElement();
  9. if(!domElement.isNull())
  10. {
  11. if(domElement.tagName() == "TestFunction")
  12. {
  13. functionItem = new QTreeWidgetItem(caseItem);
  14. functionItem->setText(0, domElement.attribute("name", "") + "()");
  15. if(domElement.attribute("name", "") == "initTestCase"
  16. || domElement.attribute("name", "") == "cleanupTestCase")
  17. {
  18. QPalette pal;
  19. functionItem->setTextColor(0, QColor(Qt::darkGray));
  20. }
  21. }
  22. else if(domElement.tagName() == "Incident")
  23. {
  24. if(domElement.attribute("type", "") == "pass")
  25. {
  26. functionItem->setText(1, "Passed!");
  27. QFont font;
  28. font.setBold(true);
  29. functionItem->setFont(1, font);
  30. QPalette pal;
  31. functionItem->setTextColor(1, QColor(Qt::darkGreen));
  32. }
  33. else
  34. {
  35. functionItem->setText(1, "Failed!");
  36. QFont font;
  37. font.setBold(true);
  38. functionItem->setFont(1, font);
  39. functionItem->setTextColor(1, QColor(Qt::red));
  40. }
  41. }
  42. else if(domElement.tagName() == "Description")
  43. functionItem->setText(2, domElement.text());
  44. }
  45. }
  46. readReport(domNode);
  47. domNode = domNode.nextSibling();
  48. }
  49. }
    Evgenii Legotckoi
    • Sept. 4, 2019, 12:36 p.m.
    • (edited)
    • The answer was marked as a solution.

    Добрый день.

    Не уверен в полной правильности того, что я написал, но ваш код по идее должен быть переписан следующим образом

    1. #include <QDomDocument>
    2.  
    3. void readElements(const QDomElement& element)
    4. {
    5. QDomNode childNode = element.firstChild();
    6. while (!childNode.isNull())
    7. {
    8. QDomElement childElement = childNode.toElement();
    9. qDebug() << qPrintable(" " + childElement.tagName());
    10. if (childElement.hasChildNodes())
    11. {
    12. readElements(childElement);
    13. }
    14. childNode = childNode.nextSibling();
    15. }
    16. }
    17.  
    18.  
    19. void readDoc(const QDomDocument& doc)
    20. {
    21. QDomElement docElem = doc.documentElement();
    22. readElements(docElem);
    23. }
      Intruder
      • Sept. 6, 2019, 1 a.m.

      В общем я написал вот такую функцию, которая возвращает список искомых элементов QDomElement

      1. void Descriptionlib::searchXmlElementsList(QVector<QDomElement> *domelementlist, QDomElement &domelement, const QString &searchtag)
      2. {
      3.  
      4. QDomNode domNode = domelement.firstChild();
      5. while (!domNode.isNull()) {
      6. QDomElement element = domNode.toElement();
      7. //qDebug() << qPrintable(element.tagName());
      8. if(element.tagName() == searchtag)
      9. {
      10. QDomElement resultElement = element;
      11. domelementlist->append(element);
      12. } else if(element.hasChildNodes()){
      13. searchXmlElementsList(domelementlist, element, searchtag);
      14. }
      15. domNode = domNode.nextSibling();
      16. }
      17. }

      Спасибо всем, кто откликнулся.

        Comments

        Only authorized users can post comments.
        Please, Log in or Sign up
        • Last comments
        • AK
          April 1, 2025, 11:41 a.m.
          Добрый день. В данный момент работаю над проектом, где необходимо выводить звук из программы в определенное аудиоустройство (колонки, наушники, виртуальный кабель и т.д). Пишу на Qt5.12.12 поско…
        • Evgenii Legotckoi
          March 9, 2025, 9:02 p.m.
          К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
        • VP
          March 9, 2025, 4:14 p.m.
          Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…
        • ИМ
          Nov. 22, 2024, 9:51 p.m.
          Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
        • Evgenii Legotckoi
          Oct. 31, 2024, 11:37 p.m.
          Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup