Ruslan Polupan
Ruslan PolupanApril 4, 2018, 2:54 a.m.

Парсинг логов XML формата.

Qt, XML, логи, парсинг

Доброго времени суток.

Вопрос скорее теологического плана.
Возникла необходимость представить в читабельном виде логи обмена между сервисами.
Логи такого формата:
18.04.03 03:46:19.261 [GET_DISCOUNT] TransactionNo=4709 SCardNo=2551000547876 MPosCheckId=310731 GoodsCount=1 additionalAttributeList.Count=0
18.04.03 03:46:23.598 [THTTPProtocol.Post -> request] <?xml version="1.0" encoding="windows-1251"?>
<Data><Type>GET_DISCOUNT</Type><context><partnerID>10</partnerID><locationID>4001</locationID><terminalID>4001</terminalID><posID>1</posID><cashierID>17</cashierID><cashierFullName>Милованова Полина</cashierFullName><login>user1</login><password>user1</password><cardNo>2551000547876</cardNo><cardHash>7B0C042167106DF919222D4596451393</cardHash><transactionDate>2018-04-03 03:46:19</transactionDate></context><transactionNo>4709</transactionNo><transactionHash>E7EF9D3FC4154B7CB24D386487C96149</transactionHash><online>1</online><posReceipt>0</posReceipt><terminalReceipt>310731</terminalReceipt><GoodsList><goods><code1>3</code1><code2>3</code2><code3>1</code3><name>2710124194*Бенз.А-92</name><quantity>5.25</quantity><price>28.55</price><amount>149.89</amount><amountDiscount>0.00</amountDiscount><flagDiscount>0</flagDiscount><bonusMaxRedeem>149.88</bonusMaxRedeem></goods></GoodsList><PayType>1</PayType><totalAmount>149.89</totalAmount><totalAmountBeforeDiscount>149.89</totalAmountBeforeDiscount><additionalAttributeList/></Data>

18.04.03 03:46:23.598 [THTTPProtocol.Post <- answer] <?xml version="1.0" encoding="windows-1251"?><Data xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><errorCode>0</errorCode><errorDescription>Нет ошибок</errorDescription><Messages><Message><Channel>1</Channel><MessageDescription>Общий баланс бонусов 31.84</MessageDescription></Message></Messages><bonusList><GoodsData><code1>0</code1><code2>3</code2><code3>1</code3><amount>149.89</amount><bonusIssuance>0</bonusIssuance><bonusRedeem>31.84</bonusRedeem><Discount>0</Discount><discountCode /><discountAmount>0.00</discountAmount><discountSource>0</discountSource><discountPercent>0</discountPercent></GoodsData></bonusList><clmTrnId>751008</clmTrnId><balanceActive>31.84</balanceActive><balanceTotal>31.84</balanceTotal></Data>
18.04.03 03:46:26.671 [ISSUANCE] TransactionNo=4710 SCardNo=2551000547876 MPosCheckId=310731 GoodsCount=1 additionalAttributeList.Count=0
18.04.03 03:46:33.207 [THTTPProtocol.Post -> request] <?xml version="1.0" encoding="windows-1251"?>
<Data><Type>ISSUANCE</Type><context><partnerID>10</partnerID><locationID>4001</locationID><terminalID>4001</terminalID><posID>1</posID><cashierID>17</cashierID><cashierFullName>Милованова Полина</cashierFullName><login>user1</login><password>user1</password><cardNo>2551000547876</cardNo><cardHash>7B0C042167106DF919222D4596451393</cardHash><transactionDate>2018-04-03 03:46:26</transactionDate></context><transactionNo>4710</transactionNo><transactionHash>2AA2BF06B710904EC2909E90C3A36F98</transactionHash><online>1</online><posReceipt>0</posReceipt><terminalReceipt>310731</terminalReceipt><GoodsList><goods><code1>3</code1><code2>3</code2><code3>1</code3><name>2710124194*Бенз.А-92</name><quantity>5.25</quantity><price>28.55</price><amount>149.89</amount><amountDiscount>0.00</amountDiscount><flagDiscount>0</flagDiscount><bonusMaxRedeem>149.88</bonusMaxRedeem></goods></GoodsList><PayType>1</PayType><totalAmount>149.89</totalAmount><totalAmountBeforeDiscount>149.89</totalAmountBeforeDiscount><additionalAttributeList/></Data>

18.04.03 03:46:33.207 [THTTPProtocol.Post <- answer] <?xml version="1.0" encoding="windows-1251"?><Data xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Messages><Message><Channel>1</Channel><MessageDescription>Карта Glusco Club:</MessageDescription></Message><Message><Channel>1</Channel><MessageDescription>2551 0005 4787</MessageDescription></Message><Message><Channel>1</Channel><MessageDescription>Стан рахунку GlusCoin:</MessageDescription></Message><Message><Channel>1</Channel><MessageDescription>Нараховано:             1.5</MessageDescription></Message><Message><Channel>1</Channel><MessageDescription>Витрачено:                0</MessageDescription></Message><Message><Channel>1</Channel><MessageDescription>Баланс:               33.34</MessageDescription></Message></Messages><errorCode>0</errorCode><errorDescription>Нет ошибок</errorDescription><bonusList><GoodsData><code1>0</code1><code2>3</code2><code3>1</code3><amount>149.89</amount><bonusIssuance>1.5</bonusIssuance><bonusRedeem>0</bonusRedeem><Discount>0</Discount><discountAmount>0.00</discountAmount><discountPercent>0</discountPercent></GoodsData></bonusList><clmTrnId>751011</clmTrnId><TotalIssuance>1.5</TotalIssuance><TotalRedeem>0</TotalRedeem><balanceActive>33.34</balanceActive><balanceTotal>33.34</balanceTotal></Data>
Вопрос в том что не могу придумать какой инструментарий использовать для разбора их и соответсвенно для наглядного отображения с возможностью поиска данных.

Буду признателен за любой совет либо комментарий.
Спасибо.
We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

6
Evgenii Legotckoi
  • April 4, 2018, 3:08 a.m.
  • (edited)

Добрый день!

Qt обладает встроенными средствами парсинга XML формата.
При этом есть два вариант
  1. Использовать QXmlStreamWriter и QXmlStreamReader - это более низкоуровневый вариант. В большинстве случаев не требуется.
  2. Использовать QDomDocument - создаёт представление документа в виде Node дерева. Более высокоуровневый вариант. Несколько удобнее. Рекомендую использовать этот вариант.
Статьи с примерами
  1. Qt/C++ - Урок 011. XML файлы в Qt - чтение и запись - используются QXmlStreamWriter и QXmlStreamReader

  2. Qt/C++ - Урок 045. SvgReader на Qt. Восстановление данных из файла SVG в QGraphicsScene - Используется QDomDocument

  3. Qt/C++ - Урок 072. Пример векторного редактора на Qt - там в исходниках есть куски кода с использованием QDomDocument.

Некоторые вопросы на форуме с использованием XML
    Ruslan Polupan
    • April 4, 2018, 8:27 a.m.

    Спасибо.

    Но чего я напрочь заблудился в QDomDocument. Толковой статьи для чайников не нашел :-)
      Ruslan Polupan
      • July 3, 2018, 6:55 a.m.

      Снова вернулся к этой теме .

      Нашел такой вот пример.
      void MainWidget::on_pushButton_clicked()
      {
          //Очистка виджета иерархического списка (дерева)
          ui->treeWidget->clear();
      
          //Создание объекта чтения xml
          QXmlStreamReader xmlReader;
          //Создание стека элементов дерева
          //Верхний элемент стека - текущий родительский элемент
          QStack<QTreeWidgetItem*> itemStack;
      
          //Загрузка текста в объект чтения
          xmlReader.addData(ui->textBrowser->toPlainText());
      
          //Цикл до конца документа
          while (!xmlReader.atEnd()){
              //Случай открывающего тега
              if (xmlReader.isStartElement()){
                  //Получение имени открывающегося тега
                  QString str = xmlReader.name().toString();
                  //Получение объекта QStringList
                  QStringList sl = str.split(",");
                  //Создание нового элемента дерева
                  QTreeWidgetItem* item = new QTreeWidgetItem(sl);
                  //Если есть родительский элемент, добавляем новый элемент в качестве дочернего
                  if (itemStack.count()>0){
                      itemStack.top()->addChild(item);
                  }
                  //иначе добавляем в качестве корневого элемента
                  else {                
                      ui->treeWidget->addTopLevelItem(item);
                  }
                  //Открывающийся тег становится текущим родительским
                  itemStack.push(item);
      //            qDebug() << xmlReader.readElementText();
              }
              //Случай закрывающего тега
              if (xmlReader.isEndElement()){
      
                  //Если стек не пуст, поднимаемся вверх по иерархии
                  if (itemStack.count()>0)
                      itemStack.pop();
              }
              //Чтение следующей единицы документа
      
              xmlReader.readNext();
          }
          //Если в процессе разбора xml-документа возникла ошибка,
          //выводим её в консоль qDebug()
          if (xmlReader.hasError())
              qDebug() << xmlReader.errorString();
      }
      Структуру выводит то что надо.

      Но что-то никак не пойму как выводить значение тегов если они есть. т.е если это не ветка списка и у тега есть значение.



        Evgenii Legotckoi
        • July 3, 2018, 4:24 p.m.

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

        А то у меня уже голова после рабочего дня не соображает.
          Ruslan Polupan
          • July 4, 2018, 1:47 a.m.

          Во вложении архив с проектом. XML в самом виджете.

            Evgenii Legotckoi
            • July 4, 2018, 5:43 p.m.

            Неудобство QXmlStreamReader заключается в том, что Вы должны знать структуру документа, из которого извлекаете данные. Поэтому нужно знать заранее все теги с которыми будете работать.


            При этом метод readElementText() сработает правильно в том случае, когда тег не содержит вложенных тегов.

            Как вариант, можете определить константное поле со списком тегов.

            class MainWidget : public QWidget
            {
                Q_OBJECT
            
            public:
                explicit MainWidget(QWidget *parent = 0);
                ~MainWidget();
            
            private slots:
                //Слот, автоматически связываемый по имени
                //с сигналом clicked() объекта кнопки pushButton
                void on_pushButton_clicked();
            private:
                Ui::MainWidget *ui;
            
                // Добавляем список тегов, из которых нужно извлечь данные
                const QStringList ELEMENTS_WITH_TEXT = {
                    "Type", "partnerID", "locationID", "terminalID", "posID"
                };
            };

            А вот вам исправленный цикл, который распарсит те данные, которые должны содержать только текст.
            //Цикл до конца документа
                while (!xmlReader.atEnd()) {
                    //Случай открывающего тега
                    if (xmlReader.isStartElement()){
                        //Получение имени открывающегося тега
                        QString str = xmlReader.name().toString();
            
                        //Получение объекта QStringList
                        if (ELEMENTS_WITH_TEXT.contains(str))
                        {
                            str = str.append(" " + xmlReader.readElementText());
                        }
            
                        //Создание нового элемента дерева
                        QTreeWidgetItem* item = new QTreeWidgetItem(QStringList() << str);
                        //Если есть родительский элемент, добавляем новый элемент в качестве дочернего
                        if (itemStack.count()>0){
                            itemStack.top()->addChild(item);
                        }
                        //иначе добавляем в качестве корневого элемента
                        else {                
                            ui->treeWidget->addTopLevelItem(item);
                        }
                        //Открывающийся тег становится текущим родительским
                        itemStack.push(item);
                    }
                    //Случай закрывающего тега
                    if (xmlReader.isEndElement()){
            
                        //Если стек не пуст, поднимаемся вверх по иерархии
                        if (itemStack.count()>0)
                            itemStack.pop();
                    }
                    //Чтение следующей единицы документа
            
                    xmlReader.readNext();
                }

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

              Comments

              Only authorized users can post comments.
              Please, Log in or Sign up
              г
              • ги
              • April 23, 2024, 3:51 p.m.

              C++ - Test 005. Structures and Classes

              • Result:41points,
              • Rating points-8
              l
              • laei
              • April 23, 2024, 9:19 a.m.

              C ++ - Test 004. Pointers, Arrays and Loops

              • Result:10points,
              • Rating points-10
              l
              • laei
              • April 23, 2024, 9:17 a.m.

              C++ - Тест 003. Условия и циклы

              • Result:50points,
              • Rating points-4
              Last comments
              k
              kmssrFeb. 8, 2024, 6:43 p.m.
              Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
              Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
              EVA
              EVADec. 25, 2023, 10:30 a.m.
              Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
              J
              JonnyJoDec. 25, 2023, 8:38 a.m.
              Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
              G
              GvozdikDec. 18, 2023, 9:01 p.m.
              Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
              Now discuss on the forum
              G
              GarApril 22, 2024, 5:46 a.m.
              Clipboard Как скопировать окно целиком в clipb?
              DA
              Dr Gangil AcademicsApril 20, 2024, 7:45 a.m.
              Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
              a
              a_vlasovApril 14, 2024, 6:41 a.m.
              Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
              Павел Дорофеев
              Павел ДорофеевApril 14, 2024, 2:35 a.m.
              QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
              f
              fastrexApril 4, 2024, 4:47 a.m.
              Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

              Follow us in social networks