1

我对在 C++ 中使用 XML 很陌生,我正在尝试解析要下载的文件列表。我使用的 XML 文件是通过 PHP 生成的,如下所示:

<?xml version="1.0"?>
<FileList>
  <File Name="xxx" Path="xxx" MD5="xxx" SHA1="xxx"/>
</FileList>

我在 C++ 中使用的代码如下,我使用一些在线教程(它包含在一些全局函数中)得出的:

tinyxml2::XMLDocument doc;

doc.LoadFile("file_listing.xml");
tinyxml2::XMLNode* pRoot = doc.FirstChild();
tinyxml2::XMLElement* pElement = pRoot->FirstChildElement("FileList");
if (pRoot == nullptr)
{
    QString text = QString::fromLocal8Bit("Error text in french");
    //other stuff
}
else
{
    tinyxml2::XMLElement* pListElement = pElement->FirstChildElement("File");
    while (pListElement != nullptr)
    {
        QString pathAttr = QString::fromStdString(pListElement->Attribute("Path"));
        QString md5Attr = QString:: fromStdString(pListElement->Attribute("MD5"));
        QString sha1Attr = QString::fromStdString(pListElement->Attribute("SHA1"));

        QString currentPath = pathAttr.remove("path");
        QString currentMd5 = this->fileChecksum(currentPath, QCryptographicHash::Md5);
        QString currentSha1 = this->fileChecksum(currentPath, QCryptographicHash::Sha1);

        QFile currentFile(currentPath);

        if (md5Attr != currentMd5 || sha1Attr != currentSha1 || !currentFile.exists())
        {
            QString url = "url" + currentPath;
            this->downloadFile(url);
        }

        pListElement = pListElement->NextSiblingElement("File");
    }

问题是,我在以下行收到类似“访问冲突,这是 nullptr”的错误:

tinyxml2::XMLElement* pListElement = pElement->FirstChildElement("File");

由于在编码方面我远非专业人士,并且我已经在互联网上上下搜索过,我希望这里有人可以为我提供一些指导。

祝你有美好的一天,伙计们。

4

2 回答 2

1

根据tinyxml2::XMLNode FirstChild() 的参考:

获取第一个子节点,如果不存在,则为 null。

因此,此行将获得根节点:

tinyxml2::XMLNode* pRoot = doc.FirstChild();

这意味着当您尝试在根节点中查找 FileList 节点时,它会返回 null。

为避免访问冲突,请在使用它们之前检查您的指针是否有效。有一个针对 pRoot 的 if 检查,但是在它尝试调用 pRoot 上的函数之前的那一行。没有 if 检查 pElement 所以这就是你得到访问冲突的原因。除了检查指针是否有效之外,还可以考虑添加带有日志记录的 else 块来说明出了什么问题(例如“找不到元素 X”)。从长远来看,这将对您有所帮助 - XML 解析是一种痛苦,即使使用像 Tinyxml 这样的库,也总是存在这样的初期问题,因此养成检查指针和注销有用消息的习惯肯定会得到回报。

于 2020-06-02T23:02:33.063 回答
1

我不知道你是否有可用的 C++17,但你可以通过使用auto*and来消除很多噪音if-init-expressions(或者依赖于指针可以隐式转换为布尔值的事实。)

您的代码的主要问题是您没有使用XMLElement*,而是使用XMLNode. 该函数tinyxml2::XMLDocument::RootElement()会自动为您获取最顶层的元素。

因为您在顶部有一个 xml 声明,所以FirstChild返回...没有任何子级,因此其余代码失败。

通过使用RootElementtinyxml 可以跳过任何前导的非元素节点(注释、文档类型等)并给您<FileList>


    tinyxml2::XMLDocument doc;
    auto err = doc.LoadFile("file_listing.xml");
    if(err != tinyxml2::XML_SUCCESS) {
        //Could not load file. Handle appropriately.
    } else {
        if(auto* pRoot = doc.RootElement(); pRoot == nullptr) {
            QString text = QString::fromLocal8Bit("Error text in french");
            //other stuff
        } else {
            for(auto* pListElement = pRoot->FirstChildElement("File");
                pListElement != nullptr;
                pListElement = pListElement->NextSiblingElement("File"))
            {
                QString pathAttr = QString::fromStdString(pListElement->Attribute("Path"));
                QString md5Attr = QString:: fromStdString(pListElement->Attribute("MD5"));
                QString sha1Attr = QString::fromStdString(pListElement->Attribute("SHA1"));

                QString currentPath = pathAttr.remove("path");
                QString currentMd5 = this->fileChecksum(currentPath, QCryptographicHash::Md5);
                QString currentSha1 = this->fileChecksum(currentPath, QCryptographicHash::Sha1);

                QFile currentFile(currentPath);
                if(md5Attr != currentMd5 || sha1Attr != currentSha1 || !currentFile.exists()) {
                    QString url = "url" + currentPath;
                    this->downloadFile(url);
                }
            }
        }
    }

于 2020-06-02T23:48:12.287 回答