Чтение тегов XML внутри StartElement (QXmlStreamReader)
Итак, я пытаюсь прочитать XML-документ небольшого размера. Это структурировано так:
<project identifier="project1">
<author>Joe Smith</author>
<author2>Rick Jones</author2>
<path>projects/internal/project2</path>
<version>1.51</version>
</project>
<project identifier="project2">
<author>Terry Chimes</author>
<author>Janie Jones</author>
<path>projects/external/project2</path>
<version>19.77</version>
</project>
... и так далее, для нескольких сотен проектов.
Я использую Qt5.10 QXmlStreamReader
, которые, возможно, были созданы (или задокументированы) садистами.
Я могу найти каждого project
используя xmlReader.readNextStartElement
- или читая тег за тегом, пока я не найду один с внутренними атрибутами (только project
теги имеют атрибуты в этом файле).
Но как только я прочитал один из этих родительских элементов, QXmlStreamReader
всасывает каждый тег до его закрытия </project>
тег. Проблема в том, что мне нужно получить некоторые из этих данных, в данном случае, что внутри <path></path>
теги.
Я могу получить все взломанные данные с xmlReader.readElementText(QXmlStreamReader::IncludeChildElements
, но это всего лишь один большой дамп данных без тегов.
Кто-нибудь знает, как можно "перемотать" и прочитать внутренние теги? Или помешать потоковому считывателю броситься вперед и высосать все данные?
1 ответ
Наиболее вероятным объяснением является то, что вы делаете что-то не так, QXmlStreamReader
не следует пропускать внутренние элементы при разборе документа. Вы не предоставили свой исходный код, поэтому невозможно сказать, что именно вы сделали неправильно.
Вот мой пример кода, который отлично работает на примере, очень похожем на ваш с Qt 5.9.2 на macOS 10.13.2:
#include <QCoreApplication>
#include <QDebug>
#include <QXmlStreamReader>
#include <QFile>
#include <QHash>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
if (argc != 2) {
qWarning() << "Usage: " << argv[0] << " <file>";
return 1;
}
QFile file(argv[1]);
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Failed to open file " << argv[1] << " for reading";
return 1;
}
QXmlStreamReader reader(&file);
QString currentProjectId;
QHash<QString,QString> pathByProjectId;
while(!reader.atEnd())
{
reader.readNext();
if (reader.isStartDocument()) {
continue;
}
if (reader.isEndDocument()) {
break;
}
if (reader.isStartElement())
{
QStringRef elementName = reader.name();
if (elementName == "project") {
QXmlStreamAttributes attrs = reader.attributes();
currentProjectId = attrs.value("identifier").toString();
}
else if (elementName == "path") {
pathByProjectId[currentProjectId] = reader.readElementText(QXmlStreamReader::IncludeChildElements);
}
continue;
}
}
for(auto it = pathByProjectId.constBegin(),
end = pathByProjectId.constEnd(); it != end; ++it)
{
qDebug() << "Path for project " << it.key() << ": " << it.value();
}
file.close();
return 0;
}
Вот ваш слегка измененный пример, который я передаю в этот пример программы:
<?xml version="1.0" encoding="UTF-8"?>
<body>
<project identifier="project1">
<author>Joe Smith</author>
<author2>Rick Jones</author2>
<path>projects/internal/project1</path>
<version>1.51</version>
</project>
<project identifier="project2">
<author>Terry Chimes</author>
<author>Janie Jones</author>
<path>projects/external/project2</path>
<version>19.77</version>
</project>
</body>
То, что я добавил к вашему образцу, - это версия XML / объявление кодировки + высокий уровень body
пометка для предотвращения QXmlStreamReader
думать первым project
тег является корневым элементом для всего документа. Я также изменил путь для первого проекта, чтобы он отличался от второго проекта.
И вот вывод, который я получил:
Path for project "project1" : "projects/internal/project1"
Path for project "project2" : "projects/external/project2"