I'd like to save custom class to XML using QSettings. But I always get XML without structure members.
#include <QCoreApplication>
#include <QtCore/qdatastream.h>
#include <qxmlstream.h>
#include <qdebug.h>
#include <QtCore/QSettings>
#include <QMetaType>
struct Interface_struct
{
QString name;
QString ip;
};
Q_DECLARE_METATYPE(Interface_struct)
QDataStream& operator <<(QDataStream& out, const Interface_struct& s)
{
out << s.name << s.ip;
return out;
}
QDataStream& operator >>(QDataStream& in, Interface_struct& s)
{
in >> s.name;
in >> s.ip;
return in;
}
static bool readXmlFile(QIODevice &device, QSettings::SettingsMap &map)
{
qDebug()<< "read";
QXmlStreamReader reader(&device);
QString key;
while(!reader.atEnd())
{
reader.readNext();
if( reader.isStartElement() && reader.tokenString() != "Settings")
{
if( reader.text().isNull() )
{
// key = Settings
if(key.isEmpty())
{
key = reader.tokenString();
}
// key = Settings/Intervall
else
{
key += "/" + reader.tokenString();
}
}
else
{
map.insert(key, reader.text().data());
}
}
}
return true;
}
static bool writeXmlFile(QIODevice &device, const QSettings::SettingsMap &map)
{
qDebug()<< "write";
QXmlStreamWriter writer(&device);
writer.writeStartDocument("1.0");
writer.writeStartElement("Settings");
foreach(QString key, map.keys())
{
foreach(QString elementKey, key.split("/"))
{
writer.writeStartElement(elementKey);
}
writer.writeCharacters(map.value(key).toString());
writer.writeEndElement();
}
writer.writeEndElement();
writer.writeEndDocument();
return true;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qRegisterMetaType<Interface_struct>("Interface_struct");
qRegisterMetaTypeStreamOperators<Interface_struct>("Interface_struct");
{
Interface_struct s;
s.name = QString("br03000");
s.ip = QString("172.16.222.5");
const QSettings::Format xml_format =
QSettings::registerFormat("xml", readXmlFile, writeXmlFile);
if(xml_format == QSettings::InvalidFormat)
{
qDebug() << "InvalidFormat!";
return 0;
}
QSettings::setPath(xml_format, QSettings::UserScope, "/home/farit/test/");
QSettings settings(xml_format, QSettings::UserScope, "xml_cfg");
settings.setValue("network", QVariant::fromValue(s));
}
{
QSettings::Format xml_format =
QSettings::registerFormat("xml", readXmlFile, writeXmlFile);
QSettings::setPath(xml_format, QSettings::UserScope, "/home/farit/test/");
QSettings settings(xml_format, QSettings::UserScope, "xml_cfg");
QVariant value = settings.value("network");
Interface_struct interface = value.value<Interface_struct>();
qDebug() << "TEST: " << interface.name << interface.ip;
}
return 0;
}
I get this output:
read
write
read
TEST: "" ""
Press <RETURN> to close this window...
And XML looks like this:
<?xml version="1.0" encoding="UTF-8"?><Settings><network></network></Settings>
How can I save structure members of custom class to XML using QSettings?
UPDATE: I'm sorry, I forgot to mention, that is supposed to be done in Qt4.
Related
How to block program execution until callback function complete execution ?
From my main() i launch interface.getImage(); function who want to get images from our database. When we receive images the callback function void InterfaceColliseo::dataReceived (std::shared_ptr data) start to execute.
But I have a problem my program main() terminate before my callback function execution ?
main.cpp
int main(){
InterfaceColliseo interface;
IMAGE = true;
interface.getImage();
// want to block program here
return 0;
}
callback function
void InterfaceColliseo::dataReceived (std::shared_ptr<IData> data)
{
if (!data->isValid())
return;
const unsigned char* twoDImageData = data->get2DImageData();
int width2DImageData = data->getWidth2DImageData();
int height2DImageData = data->getHeight2DImageData();
const unsigned char* disparityData = data->getDisparityData();
int widthDisparityData = data->getWidthDisparityData();
int heightDisparityData = data->getHeightDisparityData();
if(IMAGE) {
saveImage(twoDImageData, width2DImageData, height2DImageData,
disparityData, widthDisparityData, heightDisparityData);
IMAGE = false;
}
if(ACQUISATION){
QList<GstObservationBasic> detectorData = data->getObstaclesData();
getObstacles(detectorData);
}
}
I think you just can use thread from std. When you use join, the main thread will wait until joined thread will finish his job.
#include <thread>
//in main
std::thread myThread(interface.getImage);
myThread.join();
#include "interface_colliseo.h"
std::mutex mtx;
std::condition_variable cv;
bool IMAGE;
bool ACQUISATION;
InterfaceColliseo::InterfaceColliseo(){
}
void InterfaceColliseo::startStreaming(){
dataReceiver = _device->getDataReceiver();
start();
}
void InterfaceColliseo::getImage(){
dataReceiver = _device->getDataReceiver();
start();
}
InterfaceColliseo::InterfaceColliseo(QString IP): _IP(IP) {
qDebug() << "INDUS-5: IP server: " << _IP;
qDebug() << "INDUS-5: Connecting to sensor...";
_colliseoClient.setIPServer(_IP);
}
bool InterfaceColliseo::connect2UT(){
QString path = qApp->applicationDirPath()+"/Configuration.ini";
QSettings config(path, QSettings::IniFormat);
_IP = config.value("Connection/IP","10.0.3.144").toString();
_colliseoClient.setIPServer(_IP);
_device = _colliseoClient.getDevice();
_device->connectSensor();
bool connect = _device->isConnected();
return connect;
}
QString InterfaceColliseo::sensorName(){
return _device->getDeviceDiagnostics()->getOperatingData()
->getDeviceInformation()->getOrderNumber();
}
QString InterfaceColliseo::sensorFirmwareVersion(){
return _device->getDeviceDiagnostics()->getOperatingData()
->getDeviceInformation()->getFirmwareVersion();
}
QString InterfaceColliseo::getSensorHeadPN(QString sensor){
return _device->getDeviceDiagnostics()->getOperatingData()
->getDeviceInformation()->getSensorHeadPN(sensor);
}
QString InterfaceColliseo::getEvaluationUnitSN(){
return _device->getDeviceDiagnostics()->getOperatingData()
->getDeviceInformation()->getEvaluationUnitSN();
}
QString InterfaceColliseo::getEvaluationUnitPN(){
return _device->getDeviceDiagnostics()->getOperatingData()
->getDeviceInformation()->getEvaluationUnitPN();
}
QString InterfaceColliseo::getEvaluationUnitFirmwareVersion(){
return _device->getDeviceDiagnostics()->getOperatingData()
->getDeviceInformation()->getEvaluationUnitFirmwareVersion();
}
QString InterfaceColliseo::getEstimatedAngleX(){
return _device->getDeviceDiagnostics()->getOperatingData()
->getDeviceInformation()->getEstimatedAngleX();
}
QString InterfaceColliseo::getEstimatedAngleZ(){
return _device->getDeviceDiagnostics()->getOperatingData()
->getDeviceInformation()->getEstimatedAngleZ();
}
QString InterfaceColliseo::getEstimatedHeight(){
return _device->getDeviceDiagnostics()->getOperatingData()
->getDeviceInformation()->getEstimatedHeight();
}
void InterfaceColliseo::saveImage(const unsigned char*twoDImageData,
int width2DImageData, int height2DImageData,
const unsigned char*disparityData,
int widthDisparityData, int disptHeight){
Configuration configuration;
QString logFolder = configuration.getLogFolder();
QImage imgRight(twoDImageData, width2DImageData, height2DImageData, QImage::Format_Indexed8);
QImage imgDisparity(disparityData, widthDisparityData, disptHeight, QImage::Format_Indexed8);
QPixmap imgRght = QPixmap::fromImage(imgRight);
QPixmap imgDisp = QPixmap::fromImage(imgDisparity);
QString rghtImgPath = logFolder + "raw_image.png";
QString dispImgPath = logFolder + "disp_image.png";
imgRght.save(rghtImgPath, "PNG");
imgDisp.save(dispImgPath, "PNG");
}
void InterfaceColliseo::getObstacles(QList<GstObservationBasic> detectorData){
if (detectorData.size() == 0)
{
qDebug() << "Obstacles: no detected obstacles.";
return;
}
Configuration config;
config.writeLog("***************Obstacles List Acquisation******************");
Q_FOREACH(const GstObservationBasic &obs, detectorData)
{
qDebug() << "Obstacles: " << gstObservationToString(obs);
config.writeLog(gstObservationToString(obs));
}
}
void InterfaceColliseo::dataReceived (std::shared_ptr<IData> data)
{
if (!data->isValid())
return;
const unsigned char* twoDImageData = data->get2DImageData();
int width2DImageData = data->getWidth2DImageData();
int height2DImageData = data->getHeight2DImageData();
const unsigned char* disparityData = data->getDisparityData();
int widthDisparityData = data->getWidthDisparityData();
int heightDisparityData = data->getHeightDisparityData();
if(IMAGE) {
saveImage(twoDImageData, width2DImageData, height2DImageData,
disparityData, widthDisparityData, heightDisparityData);
IMAGE = false;
}
if(ACQUISATION){
QList<GstObservationBasic> detectorData = data->getObstaclesData();
getObstacles(detectorData);
ACQUISATION = false;
}
}
void InterfaceColliseo::start() {
dataReceiver->addListener(this);
if(dataReceiver->isListening())
dataReceiver->stopListening();
dataReceiver->startListening();
_device->triggerSingleImageAcquisition();
}
In TestGroup_Person, when I retrieve a QSharedPointer<-JB_TableRowProt> from JB_PersonDao and assign it to QSharedPointer<-JB_TableRowProt> aGroup_Person (in .h), I then get this error in the methods of TestGroup_Person.
Alternatively, if I retrieve a QSharedPointer<-JB_TableRowProt> from JB_DaoProt in each method (and don't assign it to QSharedPointer<-JB_TableRowProt> aGroup_Person), it works fine.
Can someone explain to me why this assignment appears to be causing the error please?
I got this error:
QFATAL : TestGroup_Person::test_getDBTable_Name() Received signal 11
Function time: 0ms Total time: 0ms
FAIL! : TestGroup_Person::test_getDBTable_Name() Received a fatal error.
Here's the code:
main:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QStringList arguments = QCoreApplication::arguments();
QFile aFile(DATABASE_FILENAME); // remove existing SP3.db
if (aFile.exists())
aFile.remove();
map<QString, unique_ptr<QObject>> tests;
tests.emplace("group_person", make_unique<TestGroup_Person>());
if (arguments.size() >= 3 && arguments[1] == "-select") {
QString testName = arguments[2];
auto iter = tests.begin();
while(iter != tests.end()) {
if (iter->first != testName) {
iter = tests.erase(iter);
} else {
++iter;
}
}
arguments.removeOne("-select");
arguments.removeOne(testName);
}
int status = 0;
for(auto& test : tests) {
status |= QTest::qExec(test.second.get(), arguments);
}
return status;
}
TestGroup_Person.h
#include <QString>
#include <QtTest>
#include <QSharedPointer>
#include "A_DB_Classes/JB_DatabaseManager.h"
#include "A_Tables/JB_Group_Person.h"
class TestGroup_Person : public QObject
{
Q_OBJECT
public:
TestGroup_Person();
private Q_SLOTS:
void test_allFieldsEqualsFieldNames();
void test_getDBTable_FieldNames();
void test_getDBTable_Name();
void test_hasJoinTable();
void test_setValueForField();
void test_setStorageValueForField();
void test_getStorageFields();
private:
JB_DatabaseManager& mDB;
QSharedPointer<JB_TableRowProt> aGroup_Person;
};
TestGroup_Person.cpp:
TestGroup_Person::TestGroup_Person():
mDB(JB_DatabaseManager::instance())
{
aGroup_Person = mDB.aPersonDao.getJoinTableObject();
}
void TestGroup_Person::test_allFieldsEqualsFieldNames()
{
const QVector<QString>& aVector = aGroup_Person->getDBTable_FieldNames();
const QList<QString> aList = aGroup_Person->getAllFieldNames();
bool isThere = true;
QString fieldName = "";
QString aResult = "This field name does not exist in all_FieldNamesAndValuesH";
for (int i = 0; i < aVector.size() && isThere; ++i) {
fieldName = aVector.at(i);
isThere = aList.contains(aVector.at(i));
}
if (isThere)
aResult = fieldName;
QCOMPARE(fieldName, QString(aResult));
}
void TestGroup_Person::test_getDBTable_FieldNames()
{
const QVector<QString>& aVector = aGroup_Person->getDBTable_FieldNames();
QString fieldName = "";
for (int i = 0; i < aVector.size(); ++i) {
fieldName = fieldName + aVector.at(i) +",";
}
QVector<QString> fieldNames;
QVector<QString> columnHeadings;
aGroup_Person->getViewableFieldNamesAndHeadings(fieldNames, columnHeadings);
bool correct = fieldNames.count() == columnHeadings.count();
if (!correct)
correct = columnHeadings.count() == 0;
QCOMPARE(correct, true);
QCOMPARE(fieldName, QString("groupID,personID,jobID,grp_per_dateTimeStamp,"));
}
void TestGroup_Person::test_getDBTable_Name()
{
QCOMPARE(aGroup_Person->getDBTable_Name(), QString("Group_Person"));
}
Relevant method of JB_DaoProt:
QSharedPointer<JB_TableRowProt> JB_DaoProt::getJoinTableObject()
{
JB_TableRowProt* aJoinTable = new_JoinTableRowProt();
QSharedPointer<JB_TableRowProt> pJoinTable(aJoinTable);
return pJoinTable;
}
I am using qDebug(), qInfo() and so on in combination of qInstallMessageHandler to write my logfiles. I also get an output on my batch screen, when executing my application.
I only found QT_NO_DEBUG_OUTPUT, but I want to toggle this configuration while run-time. Is there a way to prevent Qt from writing to std output?
sadly no, you only get access to the messages, but cannot prevent from beeing written to std output.
That's false in Qt 5 at the very least. The message printing code looks as follows: you can clearly see that only the message handler is being used:
if (grabMessageHandler()) {
// prefer new message handler over the old one
if (msgHandler.load() == qDefaultMsgHandler
|| messageHandler.load() != qDefaultMessageHandler) {
(*messageHandler.load())(msgType, context, message);
} else {
(*msgHandler.load())(msgType, message.toLocal8Bit().constData());
}
ungrabMessageHandler();
} else {
fprintf(stderr, "%s\n", message.toLocal8Bit().constData());
}
As you can see, the fprintf(stderr, ...) is a fallback only if recursion is detected from within the messageHandler itself.
Thus, all you need to prevent any debug output is to implement and set your own messageHandler.
To completely turn off all the debug output in Qt, the following works:
#include <QtCore>
int main() {
qDebug() << "I'm not quiet at all yet";
qInstallMessageHandler(+[](QtMsgType, const QMessageLogContext &, const QString &){});
qDebug() << "I'm very, very quiet";
}
In any case, a sensible implementation of an application-wide file logger might look as follows - it doesn't recreate the QTextStream unnecessarily; it uses QString::toUtf8() instead, and explicitly writes line endings.
#include <QtCore>
class Logger {
static struct Data {
Logger *instance;
QtMessageHandler chainedHandler;
} d;
bool m_isOpen;
QFile m_logFile;
QtMessageHandler m_oldHandler = {};
static void handler(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
if (d.instance)
d.instance->log(msg);
if (d.chainedHandler)
d.chainedHandler(type, context, msg);
}
public:
enum ChainMode { DontChain, Chain };
Logger() {
Q_ASSERT(!instance());
m_logFile.setFileName("myLog.txt");
m_isOpen = m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
d.instance = this;
}
~Logger() { uninstallHandler(); }
bool isOpen() const { return m_isOpen; }
void installHandler(ChainMode mode) {
Q_ASSERT(!m_oldHandler);
m_oldHandler = qInstallMessageHandler(handler);
if (mode == Chain)
d.chainedHandler = m_oldHandler;
}
void uninstallHandler() {
if (m_oldHandler) {
m_oldHandler = nullptr;
d.chainedHandler = nullptr;
qInstallMessageHandler(m_oldHandler);
}
}
/// This method is *not* thread-safe. Use with a thread-safe wrapper such as `qDebug`.
void log(const QString & msg) {
if (isOpen()) {
m_logFile.write(msg.toUtf8());
m_logFile.write("\n", 1);
}
}
/// Closes the log file early - this is mostly used for testing.
void endLog() {
uninstallHandler();
m_logFile.close();
}
static Logger *instance() { return d.instance; }
};
Logger::Data Logger::d;
template <typename T> QByteArray streamOutputFor(const T &data) {
QBuffer buf;
buf.open(QIODevice::ReadWrite | QIODevice::Text);
QTextStream s(&buf);
s << data << endl;
buf.close();
return buf.data();
}
QByteArray readEnd(const QString &fileName, int count) {
QFile file(fileName);
if (file.open(QIODevice::ReadOnly | QIODevice::Text) && file.size() >= count) {
file.seek(file.size() - count);
return file.readAll();
}
return {};
}
void test() {
auto const entry = QDateTime::currentDateTime().toString().toUtf8();
Q_ASSERT(Logger::instance()->isOpen());
qDebug() << entry.data();
Logger::instance()->endLog();
auto reference = streamOutputFor(entry.data());
auto readback = readEnd("myLog.txt", reference.size());
Q_ASSERT(!reference.isEmpty());
Q_ASSERT(readback == reference);
}
int main() {
Logger logger;
logger.installHandler(Logger::DontChain);
qDebug() << "Something or else";
test();
}
I'm trying to find a solution that in case that a validation is not successful because there is more then one error in the XML file the Qt MessageHandler(line, column, description etc. ) is able to show every error in the XML data not just the first one that occurs in the XML file.
Example:
I have an error in line: 65 (see pic)
but there are also errors in line :78,83,95 but it dose not show it only shows the first one.
Is there a solution for this case? And if yes how?
My Code looks like this:
MessageHandler messageHandler;
QFile xsdfile("....xsd");
xsdfile.open(QIODevice::ReadOnly);
QXmlSchema schema;
schema.setMessageHandler(&messageHandler);
bool errorOccurred = false;
if (schema.load(&xsdfile, QUrl::fromLocalFile(xsdfile.fileName())) == false)
errorOccurred = true;
else
{
QXmlSchemaValidator xmlvalidator(schema);
QFile xmlfile("......xml");
xmlfile.open(QIODevice::ReadOnly);
if (!xmlvalidator.validate(&xmlfile, QUrl::fromLocalFile(xmlfile.fileName())))
errorOccurred = true;
xmlfile.close();
}
xsdfile.close();
if (errorOccurred) {
QString qs = messageHandler.statusMessage();
cout << "Line: " << messageHandler.line() << "\n" << "Row: " << messageHandler.column() << "\n" << "ErrorMessage: ";
std::cout << qs.toUtf8().constData() << std::endl;
return -1;
}
else {
return 0;
}
And my MessageHandler class looks like this:
class MessageHandler : public QAbstractMessageHandler
{
public:
MessageHandler()
: QAbstractMessageHandler(0)
{
}
QString statusMessage() const
{
return m_description;
}
int line() const
{
return m_sourceLocation.line();
}
int column() const
{
return m_sourceLocation.column();
}
protected:
virtual void handleMessage(QtMsgType type, const QString &description,
const QUrl &identifier, const QSourceLocation &sourceLocation)
{
Q_UNUSED(type);
Q_UNUSED(identifier);
m_description = description;
m_sourceLocation = sourceLocation;
}
private:
QString m_description;
QSourceLocation m_sourceLocation;
};
Thanks :)
I think you need to write a custom validator to catch all errors. You can modify this example code to catch all errors.
struct NodeProperties
{
NodeProperties()
{
values.resize(names.size());
}
std::vector<int> values;
static QStringList names;
static QString rootName;
static QString childName;
};
QString NodeProperties::rootName = "static_route";
QString NodeProperties::childName = "molenet";
QStringList NodeProperties::names = QList<QString>() << "node_id"
<< "nextHop_id"
<< "sink_id"
<< "delay_before_send"
<< "delay_before_sleep";
QList<NodeProperties> nodesProperties;
bool parseXMLFile()
{
QXmlStreamReader xmlStreamReader;
QString xmlFile;
xmlFile = QFileDialog::getOpenFileName(this,
tr("Open XML file"), QDir::currentPath(), tr("XML (*.xml)"));
if(xmlFile.isEmpty())
return false;
QFile file(xmlFile);
if (!file.open(QFile::ReadOnly | QFile::Text))
{
QMessageBox::warning(this,tr("Error: Cannot read file ..."),
(xmlFile+" " + file.errorString() ));
return false;
}
nodesProperties.clear();
xmlStreamReader.setDevice(&file);
xmlStreamReader.readNext();
while(!xmlStreamReader.atEnd())
{
if(xmlStreamReader.isStartElement())
{
if(xmlStreamReader.name() == NodeProperties::rootName)
xmlStreamReader.readNext();
if(xmlStreamReader.name() == NodeProperties::childName)
{
xmlStreamReader.readNext();
if(xmlStreamReader.isCharacters() )
xmlStreamReader.readNext();
if(xmlStreamReader.isStartElement())
{
NodeProperties prop;
for(int i = 0; i < NodeProperties::names.size(); ++i)
{
if(xmlStreamReader.isCharacters() )
{
xmlStreamReader.readNext();
--i;
continue;
}
if(xmlStreamReader.name() == NodeProperties::names[i])
{
prop.values[i] = xmlStreamReader.readElementText().toInt();
}
xmlStreamReader.readNext();
}
nodesProperties.push_back(prop);
}
}
}
xmlStreamReader.readNext();
}
file.close();
if (xmlStreamReader.hasError())
{
QMessageBox::warning(this,tr("Error: Failed to parse file "),
(xmlFile+" " + xmlStreamReader.errorString() ));
nodesProperties.pop_back();
}
else if (file.error() != QFile::NoError)
{
qDebug() << "Error: Cannot read file " << qPrintable(xmlFile)
<< ": " << qPrintable(file.errorString());
}
//createGraphVizFile(xmlFile);
this->xmlFile = xmlFile;
return true;
}
The XML file is:
<?xml version="1.0"?>
<static_route>
<molenet>
<node_id> 1 </node_id>
<nextHop_id> 2 </nextHop_id>
<sink_id> 254 </sink_id>
<delay_before_send> 2 </delay_before_send>
<delay_before_sleep> 30 </delay_before_sleep>
</molenet>
<molenet>
<node_id> 2 </node_id>
<nextHop_id> 3 </nextHop_id>
<sink_id> 254 </sink_id>
<delay_before_send> 4 </delay_before_send>
<delay_before_sleep> 30 </delay_before_sleep>
</molenet>
</static_route>
#include <xercesc/framework/Wrapper4InputSource.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/sax2/SAX2XMLReader.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/dom/DOMLSParser.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xercesc/sax/ErrorHandler.hpp>
#include <xercesc/sax/SAXParseException.hpp>
#include <xercesc/sax/Parser.hpp>
#include <xercesc/validators/common/Grammar.hpp>
class CErrorHandler : public xercesc::DefaultHandler
{
public:
CErrorHandler();
virtual ~CErrorHandler();
void startElement(const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname,
const XERCES_CPP_NAMESPACE::Attributes& attrs
);
void endElement(const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname
);
void characters(const XMLCh* const chars,
const XMLSize_t length
);
void fatalError(const xercesc::SAXParseException&);
};
CErrorHandler::CErrorHandler()
{
}
CErrorHandler::~CErrorHandler()
{
}
void CErrorHandler::startElement(const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname,
const xercesc::Attributes& attrs)
{
char* name = xercesc::XMLString::transcode(localname);
std::cout << name;
xercesc::XMLString::release(&name);
}
void CErrorHandler::endElement(const XMLCh* const uri,
const XMLCh* const localname,
const XMLCh* const qname)
{
char* name = xercesc::XMLString::transcode(localname);
xercesc::XMLString::release(&name);
}
void CErrorHandler::fatalError(const xercesc::SAXParseException& exception)
{
char* message = xercesc::XMLString::transcode(exception.getMessage());
std::cout << "Error: " << message << " at line: " << exception.getLineNumber() << std::endl;
xercesc::XMLString::release(&message);
}
void CErrorHandler::characters(const XMLCh* const chars,
const XMLSize_t length
)
{
}
bool validateSchema()
{
std::string XSD_SHEMA ="<?xml version=\"1.0\" encoding=\"UTF-8\" ?>...";
try
{
xercesc::XMLPlatformUtils::Initialize();
}
catch (const XERCES_CPP_NAMESPACE::XMLException& toCatch)
{
char* message = xercesc::XMLString::transcode(toCatch.getMessage());
std::cout << "Error during initialization!" << std::endl;
std::cout << "Exception message is: " << message;
XERCES_CPP_NAMESPACE::XMLString::release(&message);
return false;
}
xercesc::SAX2XMLReader* parser = xercesc::XMLReaderFactory::createXMLReader();
parser->setFeature( xercesc::XMLUni::fgSAX2CoreValidation, true);
parser->setFeature( xercesc::XMLUni::fgSAX2CoreNameSpaces, true);
xercesc::DefaultHandler* defaultHandler = new CErrorHandler();
xercesc::ContentHandler* h = new CErrorHandler();
xercesc::MemBufInputSource mis(reinterpret_cast< const XMLByte* >(XSD_SHEMA.c_str() ), XSD_SHEMA.size (), "/schema.xsd");
xercesc::Wrapper4InputSource wmis (&mis, false);
parser->loadGrammar (&wmis, xercesc::Grammar::SchemaGrammarType, true);
parser->setFeature (xercesc::XMLUni::fgXercesUseCachedGrammarInParse, true);
void* id = (void*)("file:///schema.xsd");
parser->setProperty (xercesc::XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation, id);
parser->setContentHandler(h);
parser->setErrorHandler(defaultHandler);
try
{
parser->parse(mXMLFilePath.c_str());
}
catch (const xercesc::XMLException& toCatch)
{
char* message = xercesc::XMLString::transcode(toCatch.getMessage());
std::cout << "Exception message is: "<< message << std::endl;;
xercesc::XMLString::release(&message);
return false;
}
catch (const xercesc::SAXParseException& toCatch)
{
char* message = xercesc::XMLString::transcode(toCatch.getMessage());
std::cout << "Exception message is: " << message << std::endl;;
xercesc::XMLString::release(&message);
return false;
}
catch (...)
{
std::cout << "Unexpected Exception" ;
return false;
}
delete parser;
delete defaultHandler;
return true;
}
I am trying to validate xml file with path mXMLFilePath and xsd schema in string XSD_SHEMA in c++ with Xerces lib.
I created CErrorHandler class and initialized it, set schema nolocation parameter for not setting in xml path to schema.
It build`s, but not work. Have somebody any ideas?
The Xerces library (for both parsing and loading a grammar) can handle input sources (aka classes implementing the InputSource interface). MemBufInputSource would be the class for cases when something exists only in-memory.
XMLPlatformUtils::Initialize();
XercesDOMParser* domParser;
domParser = new XercesDOMParser();
char *str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\" attributeFormDefault=\"unqualified\"> \r\n </xs:schema>";
std::string strContent = str;
xercesc::MemBufInputSource pMemBufIS((XMLByte*)strContent.c_str(),
strContent.size(), "xsd");
if (domParser->loadGrammar(pMemBufIS, Grammar::SchemaGrammarType) == NULL)
{
fprintf(stderr, "couldn't load schema\n");
return false;
}
domParser->setValidationScheme(XercesDOMParser::Val_Auto);
domParser->setDoNamespaces(true);
domParser->setDoSchema(true);
domParser->setValidationConstraintFatal(true);
domParser->setExternalNoNamespaceSchemaLocation("C:\\User\\b.xsd");
domParser->setValidationConstraintFatal(true);
domParser->parse("file.xml");
if (domParser->getErrorCount() == 0)
printf("XML file validated against the schema successfully\n");
else
printf("XML file doesn't conform to the schema\n");
#include <xercesc/sax2/SAX2XMLReader.hpp>
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include <xercesc/sax/ErrorHandler.hpp>
#include <xercesc/sax/SAXParseException.hpp>
#include <xercesc/validators/common/Grammar.hpp>
#include <xercesc/parsers/SAXParser.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/util/XMLString.hpp>
#include <string>
#include <iostream>
class CErrorHandler : public xercesc::ErrorHandler
{
public:
/** Warning message method */
void warning(const xercesc::SAXParseException& ex);
/** Error message method */
void error(const xercesc::SAXParseException& ex);
/** Fatal error message method */
void fatalError(const xercesc::SAXParseException& ex);
/** Errors resetter method */
void resetErrors();
private:
/** Based message reporter method */
void reportParseException(const xercesc::SAXParseException& ex);
};
void CErrorHandler::reportParseException(const xercesc::SAXParseException& ex)
{
char* message = xercesc::XMLString::transcode(ex.getMessage());
std::cout << message << " at line " << ex.getLineNumber() << " column " << ex.getColumnNumber() << std::endl;
xercesc::XMLString::release(&message);
}
void CErrorHandler::warning(const xercesc::SAXParseException& ex)
{
reportParseException(ex);
}
void CErrorHandler::error(const xercesc::SAXParseException& ex)
{
reportParseException(ex);
}
void CErrorHandler::fatalError(const xercesc::SAXParseException& ex)
{
reportParseException(ex);
}
void CErrorHandler::resetErrors()
{
}
class CXmlValidator
{
public:
/** Constructor method */
CXmlValidator();
/** Xml file setter method */
void setFilePath(const std::string &filePath);
/** Destructor method */
~CXmlValidator();
/** Xml file with schema validation method */
bool validateSchema();
private:
/** Xml file */
std::string mXMLFilePath;
};
CXmlValidator::CXmlValidator():
mXMLFilePath("")
{
}
CXmlValidator::~CXmlValidator()
{
}
void CXmlValidator::setFilePath(const std::string &filePath)
{
mXMLFilePath = filePath;
}
bool CXmlValidator::validateSchema()
{
std::cout << std::endl;
xercesc::XMLPlatformUtils::Initialize();
std::string xsdFile = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>...";
xercesc::SAX2XMLReader *parser = xercesc::XMLReaderFactory::createXMLReader();
xercesc::ErrorHandler *handler = new CErrorHandler();
xercesc::MemBufInputSource inMemorySchemaSource(reinterpret_cast<const XMLByte*>(xsdFile.c_str()), xsdFile.size (), "/schema.xsd");
parser->loadGrammar(inMemorySchemaSource, xercesc::Grammar::SchemaGrammarType, true);
parser->setFeature(xercesc::XMLUni::fgXercesUseCachedGrammarInParse, true);
parser->setFeature(xercesc::XMLUni::fgSAX2CoreValidation, true);
parser->setFeature(xercesc::XMLUni::fgSAX2CoreNameSpaces, true);
parser->setProperty(xercesc::XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation, const_cast<void*>(static_cast<const void*>("")));
parser->setErrorHandler(handler);
parser->parse("file.xml");
if (parser->getErrorCount() != 0)
{
std::cout << "ERROR: XML file '" << mXMLFilePath << "' not confirm to the schema" << std::endl;
return false;
}
else
{
return true;
}
}
Here is correct realizations of error handler and validator classes, if somebody will need them