Intruder14 ноября 2019 г. 11:43

Как в Qt провести процедуру валидации с помощью XSD схемы XML файла

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

Как провести валидацию (offline) файла XML? С чего начать, может быть есть какие-нибудь примеры?
Заранее благодарен за помощь.

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.
12

Добрый день.

А что в вашем понимании означает валидацию?

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

Вот сигнатура метода

bool QDomDocument::setContent(const QString &text, bool namespaceProcessing, QString *errorMsg = nullptr, int *errorLine = nullptr, int *errorColumn = nullptr)

Передаёте указатели на строку для сообщения об ошибки, на int переменную для номера строки и на int переменную для номера колонки. Если метод возвращает false, то можете уже смотреть в те переменные, там будет ошибка, её место и описание.

Евгений, добрый день.

Думаю, что Ваш вопрос правильный, я не совсем корректно сформулировал свой вопрос. Суть заключается в том, что я хочу проверить правильный ли файл мне подсовывается с точки зрения его схемы XSD. Дело в том, что я могу на вход подать любой файл формата XML. И если входной файл не соответсвует заданной схеме, то завершить дальнейшую его обработку.
Я уже написал небольшую програмку, которая этим занимается, но столкнулся в другой проблемой.
Для начала я решил проверить свою задачу вот так:

#include <QCoreApplication>

....
{
....
QFile xsdfile("D:\\XML_Schema_package\\Schemas\\wrngdata.xsd");
    xsdfile.open(QIODevice::ReadOnly);
    QXmlSchema schema;
    if(schema.load(&xsdfile, QUrl::fromLocalFile(xsdfile.fileName()))){
        if(schema.isValid()){
            qDebug() << "schema is valid";
            QFile xmlfile("D:\\S1000D_4-1_Bike-Samples\\DMC-S1000DLIGHTING-AAA-D00-00-00-00AA-057A-A_008-00_EN-US.XML");
            xmlfile.open(QIODevice::ReadOnly);
            QXmlSchemaValidator xmlvalidator(schema);
            if(xmlvalidator.validate(&xmlfile, QUrl::fromLocalFile(xmlfile.fileName()))){
                qDebug() << "Is valid";
            }
        }else {
            qDebug() << "schema is not valid";
        }
    }

    return a.exec();
    }

Получил утвердительный результат.
В моем проекте есть динамическая библиотека и я решил перенести эту часть кода в библиотеку. Вот ее объявление и описание:

static bool validate(const QString &xsdschema, const QString &xmlschema);

bool Wrngdatalib::validate(const QString &xsdschema, const QString &xmlschema)
{
    bool flag = false;
    QFile xsdfile(xsdschema);
    if(!xsdfile.open(QIODevice::ReadOnly)){
        flag = false;
    }
    QXmlSchema schema;
    if(schema.load(&xsdfile, QUrl::fromLocalFile(xsdfile.fileName()))){
        if(schema.isValid()){
            QFile xmlfile(xmlschema);
            if(!xmlfile.open(QIODevice::ReadOnly)){
                flag = false;
            }
            QXmlSchemaValidator xmlvalidator(schema);
            if(xmlvalidator.validate(&xmlfile, QUrl::fromLocalFile(xmlfile.fileName()))){
                flag = true;
            }
        }
    }
    return flag;
}

В теле программы я поправил код вот таким образом:

if(Wrngdatalib::validate("D:\\XML_Schema_package\\Schemas\\wrngdata.xsd", "D:\\S1000D_4-1_Bike-Samples\\DMC-S1000DLIGHTING-AAA-D00-00-00-00AA-057A-A_008-00_EN-US.XML")){
    qDebug() << "Is valid";
}

Но при попытке выполнить программу получаю вот такие ошибки:

Object is exist
QEventLoop: Cannot be used without QApplication
QEventLoop: Cannot be used without QApplication
QEventLoop: Cannot be used without QApplication
QEventLoop: Cannot be used without QApplication
QEventLoop: Cannot be used without QApplication
Error XSDError in http://www.s1000d.org/S1000D_4-1/xml_schema_flat/wrngdata.xsd, at line 1, column 0: Premature end of document.
Error XSDError in file:///D:/S1000D_4-1_Bike-Samples/DMC-S1000DLIGHTING-AAA-D00-00-00-00AA-057A-A_008-00_EN-US.XML, at line 8, column 304: Loaded schema file is invalid.

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

Заранее благодарен за ответ и помощь.

Что это такое Wrngdatalib ? Это namespace ?

Скорее всего проблема в том, что те объекты тех классов, которые там присутствуют для обработки xml наследованы от QObject, но в том методе внутри библиотеки они не находят возможности использования QEventLoop. Попробуйте в библиотеке написать класс для валидации XML, который будет наследован от QObject. А в коде основной программы создавайте инстанс этого класса и только потом вызывайте метод validate -

Что это такое Wrngdatalib ? Это namespace ?
Wrngdatalib - Это class.
Что-то не получилось. Может я снова делаю что-то не то?
Создал класс:

#ifndef XMLFUNCTION_H
#define XMLFUNCTION_H

#include <QObject>
#include "wrngdatalib_global.h"

class WRNGDATALIBSHARED_EXPORT xmlfunction : public QObject
{
    Q_OBJECT
public:
    explicit xmlfunction(QObject *parent = nullptr);

    bool validate(const QString &xsdschema, const QString &xmlschema);

signals:

public slots:

};

#endif // XMLFUNCTION_H

Описание функции:

#include "xmlfunction.h"
#include <QtXmlPatterns/QXmlSchema>
#include <QtXmlPatterns/QXmlSchemaValidator>
#include <QFile>
xmlfunction::xmlfunction(QObject *parent) : QObject(parent)
{

}

bool xmlfunction::validate(const QString &xsdschema, const QString &xmlschema)
{
    bool flag = false;
    QFile xsdfile(xsdschema);
    if(!xsdfile.open(QIODevice::ReadOnly)){
        flag = false;
    }
    QXmlSchema schema;
    if(schema.load(&xsdfile, QUrl::fromLocalFile(xsdfile.fileName()))){
        if(schema.isValid()){
            QFile xmlfile(xmlschema);
            if(!xmlfile.open(QIODevice::ReadOnly)){
                flag = false;
            }
            QXmlSchemaValidator xmlvalidator(schema);
            if(xmlvalidator.validate(&xmlfile, QUrl::fromLocalFile(xmlfile.fileName()))){
               flag = true;
            }
        }
    }
    return flag;
}

И сама программа:

#include <QCoreApplication>
#include <QVector>
#include <QDebug>
#include <QtXmlPatterns/QXmlSchema>
#include <QtXmlPatterns/QXmlSchemaValidator>
#include "wrngdatalib.h"
#include "xmlfunction.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    xmlfunction xmlObj;
    bool aaa = xmlObj.validate("D:\\XML_Schema_package\\Schemas\\wrngdata.xsd", "D:\\S1000D_4-1_Bike-Samples\\DMC-S1000DLIGHTING-AAA-D00-00-00-00AA-057A-A_008-00_EN-US.XML");
    if(aaa){
        qDebug() << "Is valid";
    }
    return a.exec();
}

Получаю туже самую ошибку.

Ага... слушайте. Дело-то походу в том, что вы используете QCoreApplication, поскольку у вас консольная программа.

Попробуйте так

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    xmlfunction xmlObj;
    bool aaa = xmlObj.validate("D:\\XML_Schema_package\\Schemas\\wrngdata.xsd", "D:\\S1000D_4-1_Bike-Samples\\DMC-S1000DLIGHTING-AAA-D00-00-00-00AA-057A-A_008-00_EN-US.XML");
    if(aaa){
        qDebug() << "Is valid";
    }
    return 0;
}

Нет, так тоже не работает. Ведь когда у меня эта часть кода по валидации была в теле программы, то все работало. Может это как-то связано с сигналами и слотами? Я просто в этом пока ну очень сильно плаваю.

Это не с сигналами и слотами связано, а с системой обработки событий в Qt.
Если использовать QApplication вместо QCoreApplication, то работает?

Евгений, почитав про эту проблему пришел к выводу, что либо нужно говорить очередь, либо все вернуть из библиотеки (dll в моем случае) в приложение, потому что в приложении все работает просто замечательно. И еще как вариант курить QEventLoop.

Я бы вернул в приложение.
Ещё задумался бы, а нужна ли действительно эта динамическая библиотека вам. Возможно, что вам достаточно будет сделать статическую библиотеку.

Евгений, доброго дня.
В динамической библиотеке помимо этого много чего еще есть. Поэтому просто хотел добавить функцию валидации перед парсингом. Функцию оставлю в приложении - это не критично. Красиво чтоли хотелось, не знаю.
Спасибо за помощь. А в чем разница между статической и динамичческой библиотекой?

Добрый день

  • динамическая - это в случае Windows dll, он лежит рядом с испоолняемым файлом.
  • статическая библиотека компилируется как самостоятельная библиотека в проекте, и будучи предкомпилированной может подключаться в другие проекты без наличия исходников, достаточно будет только заголовочных файлов. При этом статическая библиотека включается в исполняемый файл.

Понятно. Я кстати так сейчас и сделал, добавил проект в проект и т.д.
Спасибо!

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
Timeweb

Позвольте мне порекомендовать вам отличный хостинг, на котором расположен EVILEG.

В течение многих лет Timeweb доказывает свою стабильность.

Для проектов на Django рекомендую VDS хостинг

Посмотреть Хостинг
VD

C++ - Тест 001. Первая программа и типы данных

  • Результат:73баллов,
  • Очки рейтинга1
Ds

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

  • Результат:64баллов,
  • Очки рейтинга-1
o

C++ - Тест 001. Первая программа и типы данных

  • Результат:86баллов,
  • Очки рейтинга6
Последние комментарии
D:

QML - Урок 016. База данных SQLite и работа с ней в QML Qt

Добрый день, пытаюсь разобраться и подргнать пример под себя. Есть бд с огромным количеством полей. В приложении на виджетах при использовании QTableView все работает и путем простого sql запрос…

Django - Урок 039. Добавление личных сообщений и чатов на сайте - Часть 2 (Счётчик диалогов и чатов с непрочитанными сообщениями)

Добавляйте поле файла в модель сообщения. И в форме сообщения указывайте, что поле с файлом.
s

Django - Урок 023. Like Dislike система с помощью GenericForeignKey

все, я со всем разобрался!) Извините!)
s

Django - Урок 023. Like Dislike система с помощью GenericForeignKey

Доброго времени суток!) Я случайно набрел на вашу статью, и она помогла мне решить некоторые мои трудности, я прошел за вами по шагам, в попытках адаптировать это под себя, и возник вопрос. У ва…
Сейчас обсуждают на форуме
М

QML: изменение стиля при наведении и при нажатии на кнопку

enabled = false перестанет быть активной и не будет ни на что реагировать) Хм.. по-моему пробовал такое. Проверю ещё раз после работы. Ура, спасибо большо…
U

Динамическое наполнение StackView QML

Во затупил))) Спасибо за все))) StackView.push("ModuleTip1.qml") ну или в сложной иерархии StackView.push("qrc:/folder/ModuleTip1.qml") и всего делов... Не пойму, почему сра…

QEventLoop тормозит при удалении экземпляра

Думаю, что нет. Лучше вообще без исключений, но не всегда возможно.
s

Ключевое слово class

Разобрался,на стаковерфлоу нашел топик и понял почему так происходило .

Поведение пустой очереди std::queue

Спасибо, так и сделал.
О нас
Услуги
© EVILEG 2015-2020
Рекомендует хостинг TIMEWEB