Qt解析是我们在开发过程中经常使用到的,如果解析成功就可以使用了,但是我们想要解析外部命令的时候却发现无法解析,这要怎么去解决呢?下面来我们就来给大家讲解一下。
我们用实例说明Qt无法解析的外部命令的解决方法,如编译工程出现的问题如下:
mainwindow.obj : error LNK2019: 无法解析的外部符号 "public: void __thiscall signalandslot::SetData(int)" (?SetData@signalandslot@@QAEXH@Z),该符号在函数 "private: void __thiscall MainWindow::on_actionDakai_triggered(void)" (?on_actionDakai_triggered@MainWindow@@AAEXXZ) 中被引用
moc_signalandslot.obj : error LNK2001: 无法解析的外部符号 "public: void __thiscall signalandslot::SetData(int)" (?SetData@signalandslot@@QAEXH@Z)
debug\learnQT01.exe : fatal error LNK1120: 1 个无法解析的外部命令
解决办法:
方法一:将工程重新qmake,重新构建下。(不行再删除项目同名文件夹下的调试文件夹,例如:build-calculate-Desktop_Qt_5_6_0_MSVC2013_32bit-Debug文件夹)
方法二:检查是否有定义了的SOLT 函数没有实现?是否实现代码书写不正确。
方法三:检查Qt的库lib有没有正确的添加包含进来(具体可参考Qt配置教程)( 头文件都无法识别也可能是这个原因)。
方法四:代码写好后,未在*.pro文件中添加选项信息(例如:进行网络编程时,代码写完后需要在工程文件*.pro文件中添加network选项后才能编译通过。添加的信息:QT += core gui network)。
方法五:如果工程项目中有多个子项目,在子项目中如果需要调用外部类,那么需要将这个类对应的文件添加到子项目中,即在子项目的*.pro文件中引入这个类的路径。(注意:1.还要在代码中对这个类的头文件进行#include,不操作方法五,仅仅添加头文件是不行的,在linux上编译还会报"symbol lookup error"问题)。
Qt怎么解析Xml?
先给出xml如下:
<?xml version="1.0" encoding="utf-8"?> <school> <teacher> <entry name="Job"> <age>30</age> <sport>soccer</sport> </entry> <entry name="Tom"> <age>32</age> <sport>swimming</sport> </entry> </teacher> <student> <entry name="Lily"> <age>20</age> <sport>dancing</sport> </entry> <entry name="Keith"> <age>21</age> <sport>running</sport> </entry> </student> </school>
下面给出qt中解析xml的三种方式,通过解析xml,创建student列表和teacher列表。先给出存储的结构体和辅助函数:
#include #include namespace School { struct Teacher { std::string name; int age; std::string loveSport; Teacher(std::string name_, int age_, std::string loveSport_): name(std::move(name_)), age(age_), loveSport(std::move(loveSport_)) {} }; struct Student { std::string name; int age; std::string loveSport; Student(std::string name_, int age_, std::string loveSport_): name(std::move(name_)), age(age_), loveSport(std::move(loveSport_)) {} }; inline void print(std::ostream & out , const Teacher & teacher) { out << "teacher: " << teacher.name << std::endl; out << "\tage: " << teacher.age << std::endl; out << "\tfavorite sport: " << teacher.loveSport << std::endl; } inline void print(std::ostream & out , const Student & student) { out << "student: " << student.name << std::endl; out << "\tage: " << student.age << std::endl; out << "\tfavorite sport: " << student.loveSport << std::endl; } }
另外需要注意在.pro中添加
QT += xml
(1)通过QXmlStreamReader:
#include <QXmlStreamReader> #include "schooldefine.h" class XmlStreamReader { public: XmlStreamReader(); bool readFile(const QString & fileName); void printAllMembers(); private: void readSchoolMembers(); void readTeacherMembers(); void readTeacher(const QStringRef & teacherName); void readStudentMembers(); void readStudent(const QStringRef & studentName); void skipUnknownElement(); QXmlStreamReader reader; std::vector < School::Teacher > m_teachers; std::vector < School::Student > m_students; };
#include "XmlStreamReader.h" #include <QFile> #include <iostream> #include <QDebug> XmlStreamReader::XmlStreamReader() { } bool XmlStreamReader::readFile(const QString &fileName) { QFile file(fileName); if (!file.open(QFile::ReadOnly | QFile::Text)) { std::cerr << "Error: Cannot read file " << qPrintable(fileName) << ": " << qPrintable(file.errorString()) << std::endl; return false; } reader.setDevice(&file); reader.readNext(); while (!reader.atEnd()) { if (reader.isStartElement()) { if (reader.name() == "school") { readSchoolMembers(); } else { reader.raiseError(QObject::tr("Not a school file")); } } else { reader.readNext(); } } file.close(); if (reader.hasError()) { std::cerr << "Error: Failed to parse file " << qPrintable(fileName) << ": " << qPrintable(reader.errorString()) << std::endl; return false; } else if (file.error() != QFile::NoError) { std::cerr << "Error: Cannot read file " << qPrintable(fileName) << ": " << qPrintable(file.errorString()) << std::endl; return false; } return true; } void XmlStreamReader::printAllMembers() { std::cout << "All teachers: " << std::endl; for (const auto& teacher : m_teachers) { School::print(std::cout, teacher); } std::cout << "All students: " << std::endl; for (const auto& student : m_students) { School::print(std::cout, student); } } void XmlStreamReader::readSchoolMembers() { reader.readNext(); while (!reader.atEnd()) { if (reader.isEndElement()) { reader.readNext(); break; } if (reader.isStartElement()) { if (reader.name() == "teacher") { readTeacherMembers(); } else if (reader.name() == "student") { readStudentMembers(); } else { skipUnknownElement(); } } else { reader.readNext(); } } } void XmlStreamReader::readTeacherMembers() { reader.readNext(); while (!reader.atEnd()) { if (reader.isEndElement()) { reader.readNext(); break; } if (reader.isStartElement()) { if (reader.name() == "entry") { readTeacher(reader.attributes().value("name")); } else { skipUnknownElement(); } } else { reader.readNext(); } } } void XmlStreamReader::readTeacher(const QStringRef& teacherName) { reader.readNext(); int age = 0; std::string favoriteSport; while (!reader.atEnd()) { if (reader.isEndElement()) { reader.readNext(); break; } if (reader.isStartElement()) { if (reader.name() == "age") { age = reader.readElementText().toInt(); } else if (reader.name() == "sport") { favoriteSport = reader.readElementText().toStdString(); } else { skipUnknownElement(); } } reader.readNext(); } m_teachers.emplace_back(teacherName.toString().toStdString(), age, favoriteSport); } void XmlStreamReader::readStudentMembers() { reader.readNext(); while (!reader.atEnd()) { if (reader.isEndElement()) { reader.readNext(); break; } if (reader.isStartElement()) { if (reader.name() == "entry") { readStudent(reader.attributes().value("name")); } else { skipUnknownElement(); } } else { reader.readNext(); } } } void XmlStreamReader::readStudent(const QStringRef &studentName) { reader.readNext(); int age = 0; std::string favoriteSport; while (!reader.atEnd()) { if (reader.isEndElement()) { reader.readNext(); break; } if (reader.isStartElement()) { if (reader.name() == "age") { age = reader.readElementText().toInt(); } else if (reader.name() == "sport") { favoriteSport = reader.readElementText().toStdString(); } else { skipUnknownElement(); } } reader.readNext(); } m_students.emplace_back(studentName.toString().toStdString(), age, favoriteSport); } void XmlStreamReader::skipUnknownElement() { reader.readNext(); while (!reader.atEnd()) { if (reader.isEndElement()) { reader.readNext(); break; } if (reader.isStartElement()) { skipUnknownElement(); } else { reader.readNext(); } } }
(2)通过DOM方式:
#include #include #include "schooldefine.h" class DomParser { public: DomParser(); bool readFile(const QString & fileName); void printAllMembers(); private: void parseSchoolMembers(const QDomElement & element); void parseTeacherMembers(const QDomElement & element); void parseStudentMembers(const QDomElement & element); void parseTeacher(const QDomElement & element); void parseStudent(const QDomElement & element); std::vectorm_teachers; std::vectorm_students; };
#include "domparser.h" #include #include #include DomParser::DomParser() {} bool DomParser::readFile(const QString & fileName) { QFile file(fileName); if (!file.open(QFile::ReadOnly | QFile::Text)) { std::cerr << "Error: Cannot read file " << qPrintable(fileName) << ": " << qPrintable(file.errorString()) << std::endl; return false; } QString errorStr; int errorLine; int errorColumn; QDomDocument doc; if (!doc.setContent( & file, false, & errorStr, & errorLine, & errorColumn)) { std::cerr << "Error: Parse error at line " << errorLine << ", " << "column " << errorColumn << ": " << qPrintable(errorStr) << std::endl; return false; } QDomElement root = doc.documentElement(); if (root.tagName() != "school") { std::cerr << "Error: Not a school file" << std::endl; return false; } parseSchoolMembers(root); return true; } void DomParser::printAllMembers() { std::cout << "All teachers: " << std::endl; for (const auto & teacher: m_teachers) { School::print(std::cout, teacher); } std::cout << "All students: " << std::endl; for (const auto & student: m_students) { School::print(std::cout, student); } } void DomParser::parseSchoolMembers(const QDomElement & element) { QDomNode child = element.firstChild(); while (!child.isNull()) { if (child.toElement() .tagName() == "teacher") { parseTeacherMembers(child.toElement()); } else if (child.toElement() .tagName() == "student") { parseStudentMembers(child.toElement()); } child = child.nextSibling(); } } void DomParser::parseTeacherMembers(const QDomElement & element) { QDomNode child = element.firstChild(); while (!child.isNull()) { if (child.toElement() .tagName() == "entry") { parseTeacher(child.toElement()); } child = child.nextSibling(); } } void DomParser::parseStudentMembers(const QDomElement & element) { QDomNode child = element.firstChild(); while (!child.isNull()) { if (child.toElement() .tagName() == "entry") { parseStudent(child.toElement()); } child = child.nextSibling(); } } void DomParser::parseTeacher(const QDomElement & element) { auto children = element.childNodes(); auto firstChild = children.at(0) .toElement(); auto secondChild = children.at(1) .toElement(); int age = firstChild.text() .toInt(); m_teachers.emplace_back(element.attribute("name") .toStdString() , age, secondChild.text() .toStdString()); } void DomParser::parseStudent(const QDomElement & element) { auto children = element.childNodes(); auto firstChild = children.at(0) .toElement(); auto secondChild = children.at(1) .toElement(); int age = firstChild.text() .toInt(); m_students.emplace_back(element.attribute("name") .toStdString() , age, secondChild.text() .toStdString()); }
3. 采用QXmlSimpleReader方式,也就是回调函数方式:
#include #include "schooldefine.h" class SaxHandler: public QXmlDefaultHandler { public: SaxHandler(); bool readFile(const QString & fileName); void printAllMembers(); protected: bool startElement(const QString & namespaceURI , const QString & localName , const QString & qName , const QXmlAttributes & atts) override; bool endElement(const QString & namespaceURL , const QString & localName , const QString & qName) override; bool characters(const QString & ch) override; bool fatalError(const QXmlParseException & exception) override; private: bool m_isStudent = false; QString m_currentContext; std::vectorm_teachers; std::vectorm_students; };
#include "saxhandler.h" #include SaxHandler::SaxHandler() {} bool SaxHandler::readFile(const QString & fileName) { QFile file(fileName); QXmlInputSource inputSource( & file); QXmlSimpleReader reader; reader.setContentHandler(this); reader.setErrorHandler(this);; return reader.parse(inputSource); } void SaxHandler::printAllMembers() { std::cout << "All teachers: " << std::endl; for (const auto & teacher: m_teachers) { School::print(std::cout, teacher); } std::cout << "All students: " << std::endl; for (const auto & student: m_students) { School::print(std::cout, student); } } bool SaxHandler::startElement(const QString & namespaceURI , const QString & localName , const QString & qName , const QXmlAttributes & atts) { if (qName == "teacher") { m_isStudent = false; } else if (qName == "student") { m_isStudent = true; } else if (qName == "entry") { if (m_isStudent) { m_students.push_back(School::Student("", 0, "")); m_students.back() .name = atts.value("name") .toStdString(); } else { m_teachers.push_back(School::Teacher("", 0, "")); m_teachers.back() .name = atts.value("name") .toStdString(); } } else if (qName == "age") { m_currentContext.clear(); } else if (qName == "sport") { m_currentContext.clear(); } return true; } bool SaxHandler::characters(const QString & ch) { m_currentContext += ch; return true; } bool SaxHandler::endElement(const QString & namespaceURL , const QString & localName , const QString & qName) { if (qName == "age") { if (m_isStudent) { m_students.back() .age = m_currentContext.toInt(); } else { m_teachers.back() .age = m_currentContext.toInt(); } } else if (qName == "sport") { if (m_isStudent) { m_students.back() .loveSport = m_currentContext.toStdString(); } else { m_teachers.back() .loveSport = m_currentContext.toStdString(); } } m_currentContext.clear(); return true; } bool SaxHandler::fatalError(const QXmlParseException & exception) { std::cerr << "Parse error at line" << exception.lineNumber() << ", " << "column " << exception.columnNumber() << ": " << qPrintable(exception.message()) << std::endl; return false; }
Qt解析xml可以使用以上这几种方法,如果xml比较大,或者调用比较频繁,可以考虑使用QXmlStreamReader的方式去解决。最后大家如果想要了解更多json相关知识,敬请关注奇Q工具网。
推荐阅读: