Qt无法解析的外部命令怎么办?Qt怎么解析Xml?

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工具网。

推荐阅读:

java面试中有哪些锁?Java锁面试题有哪些?

java泛型方法如何使用?java泛型方法具体实例

javabean原理是什么?javabean怎么使用?