使用 TinyXML2 在 C++ 中读取 XML 文件
Reading a XML file in C++ with TinyXML2
我对在 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");
}
问题是,我在以下行中收到类似 "Access violation, this was nullptr" 的错误:
tinyxml2::XMLElement* pListElement = pElement->FirstChildElement("File");
由于我在编码方面远不是专业人士,而且我已经在网上搜索过,希望这里的人能给我一些指导。
祝大家有个美好的一天。
根据 reference for tinyxml2::XMLNodeFirstChild():
Get the first child node, or null if none exists.
因此,这一行将获得根节点:
tinyxml2::XMLNode* pRoot = doc.FirstChild();
意思是当您尝试在根节点中查找 FileList 节点时,它 returns 为空。
为避免访问冲突,请在使用前检查您的指针是否有效。有一个 pRoot 的 if 检查,但是在它试图调用 pRoot 上的函数之前的那一行。没有 if 检查 pElement,所以这就是您遇到访问冲突的原因。除了检查指针是否有效外,还可以考虑添加带有日志记录的 else 块以说明出了什么问题(例如 "could not find element X")。这将帮助你在漫长的 运行 - XML 解析是一个痛苦的过程中,即使使用像 Tinyxml 这样的库,也总是有这样的问题,所以养成检查指针和注销的习惯有用的消息一定会有所回报。
我不知道你是否有可用的 C++17,但你可以通过使用 auto*
和 if-init-expressions
(或者依赖于指针可以是隐式转换为布尔值。)
您的代码的主要问题是您没有使用 XMLElement*
,而是使用 XMLNode
。函数 tinyxml2::XMLDocument::RootElement()
自动为您获取最顶层的元素。
因为顶部有一个 xml 声明,FirstChild
returns 没有任何子项,所以其余代码失败。
通过使用 RootElement
tinyxml 知道跳过任何前导的非元素节点(注释、文档类型等)并为您提供 <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);
}
}
}
}
我对在 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");
}
问题是,我在以下行中收到类似 "Access violation, this was nullptr" 的错误:
tinyxml2::XMLElement* pListElement = pElement->FirstChildElement("File");
由于我在编码方面远不是专业人士,而且我已经在网上搜索过,希望这里的人能给我一些指导。
祝大家有个美好的一天。
根据 reference for tinyxml2::XMLNodeFirstChild():
Get the first child node, or null if none exists.
因此,这一行将获得根节点:
tinyxml2::XMLNode* pRoot = doc.FirstChild();
意思是当您尝试在根节点中查找 FileList 节点时,它 returns 为空。
为避免访问冲突,请在使用前检查您的指针是否有效。有一个 pRoot 的 if 检查,但是在它试图调用 pRoot 上的函数之前的那一行。没有 if 检查 pElement,所以这就是您遇到访问冲突的原因。除了检查指针是否有效外,还可以考虑添加带有日志记录的 else 块以说明出了什么问题(例如 "could not find element X")。这将帮助你在漫长的 运行 - XML 解析是一个痛苦的过程中,即使使用像 Tinyxml 这样的库,也总是有这样的问题,所以养成检查指针和注销的习惯有用的消息一定会有所回报。
我不知道你是否有可用的 C++17,但你可以通过使用 auto*
和 if-init-expressions
(或者依赖于指针可以是隐式转换为布尔值。)
您的代码的主要问题是您没有使用 XMLElement*
,而是使用 XMLNode
。函数 tinyxml2::XMLDocument::RootElement()
自动为您获取最顶层的元素。
因为顶部有一个 xml 声明,FirstChild
returns 没有任何子项,所以其余代码失败。
通过使用 RootElement
tinyxml 知道跳过任何前导的非元素节点(注释、文档类型等)并为您提供 <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);
}
}
}
}