C++ 为什么我不能使用 Qt 中的 QXmlStreamReader 解析 XML 文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4201175/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why can't I parse a XML file using QXmlStreamReader from Qt?
提问by neuviemeporte
I'm trying to figure out how QXmlStreamReader works for a C++ application I'm writing. The XML file I want to parse is a large dictionary with a convoluted structure and plenty of Unicode characters so I decided to try a small test case with a simpler document. Unfortunately, I hit a wall. Here's the example xml file:
我试图弄清楚 QXmlStreamReader 如何为我正在编写的 C++ 应用程序工作。我要解析的 XML 文件是一个大字典,具有复杂的结构和大量的 Unicode 字符,因此我决定尝试使用更简单的文档进行一个小型测试用例。不幸的是,我撞到了墙。这是示例 xml 文件:
<?xml version="1.0" encoding="UTF-8" ?>
<persons>
<person>
<firstname>John</firstname>
<surname>Doe</surname>
<email>[email protected]</email>
<website>http://en.wikipedia.org/wiki/John_Doe</website>
</person>
<person>
<firstname>Jane</firstname>
<surname>Doe</surname>
<email>[email protected]</email>
<website>http://en.wikipedia.org/wiki/John_Doe</website>
</person>
<person>
<firstname>Matti</firstname>
<surname>Meik?l?inen</surname>
<email>[email protected]</email>
<website>http://fi.wikipedia.org/wiki/Matti_Meik?l?inen</website>
</person>
</persons>
...and I'm trying to parse it using this code:
...我正在尝试使用以下代码解析它:
int main(int argc, char *argv[])
{
if (argc != 2) return 1;
QString filename(argv[1]);
QTextStream cout(stdout);
cout << "Starting... filename: " << filename << endl;
QFile file(filename);
bool open = file.open(QIODevice::ReadOnly | QIODevice::Text);
if (!open)
{
cout << "Couldn't open file" << endl;
return 1;
}
else
{
cout << "File opened OK" << endl;
}
QXmlStreamReader xml(&file);
cout << "Encoding: " << xml.documentEncoding().toString() << endl;
while (!xml.atEnd() && !xml.hasError())
{
xml.readNext();
if (xml.isStartElement())
{
cout << "element name: '" << xml.name().toString() << "'"
<< ", text: '" << xml.text().toString() << "'" << endl;
}
else if (xml.hasError())
{
cout << "XML error: " << xml.errorString() << endl;
}
else if (xml.atEnd())
{
cout << "Reached end, done" << endl;
}
}
return 0;
}
...then I get this output:
...然后我得到这个输出:
C:\xmltest\Debug>xmltest.exe example.xml
Starting... filename: example.xml
File opened OK
Encoding:
XML error: Encountered incorrectly encoded content.
C:\xmltest\Debug>xmltest.exe example.xml 正在
启动... 文件名:example.xml
文件打开 OK
编码:
XML 错误:遇到编码不正确的内容。
What happened? This file couldn't be simpler and it looks consistent to me. With my original file I also get a blank entry for the encoding, the entries' names() are displayed, but alas, the text() is also empty. Any suggestions greatly appreciated, personally I'm thorougly mystified.
发生了什么?这个文件再简单不过了,对我来说看起来很一致。对于我的原始文件,我也得到了一个空白的编码条目,显示了条目的名称(),但唉,文本()也是空的。任何建议都非常感谢,我个人非常困惑。
回答by neuviemeporte
I'm answering this myself as this problem was related to three issues, two of which were brought up by the responses.
我自己回答这个问题,因为这个问题与三个问题有关,其中两个是由回复提出的。
- The file actually wasn't UTF-8 encoded. I changed the encoding to iso-8859-1 and the encoding warning disappeared.
- The text() function doesn't work as I expected. I have to use readElementText() to read the entries' contents.
- When I try to readElementText() on an element that doesn't contain text, like the top-level <persons>in my case, the parser returns an "Expected character data"error and the parsing is interrupted. I find this behaviour strange (in my opinion returning an empty string and continuing would be better) but I guess as long as the specification is known, I can work around it and avoid calling this function on every entry.
- 该文件实际上不是 UTF-8 编码的。我将编码更改为 iso-8859-1 并且编码警告消失了。
- text() 函数没有按我预期的那样工作。我必须使用 readElementText() 来读取条目的内容。
- 当我尝试在不包含文本的元素上读取元素文本()时,例如我的顶级<persons>,解析器返回“预期字符数据”错误并且解析被中断。我发现这种行为很奇怪(我认为返回一个空字符串并继续会更好)但我想只要规范已知,我就可以解决它并避免在每个条目上调用此函数。
The relevant code section that works as expected now looks like this:
按预期工作的相关代码部分现在如下所示:
while (!xml.atEnd() && !xml.hasError())
{
xml.readNext();
if (xml.isStartElement())
{
QString name = xml.name().toString();
if (name == "firstname" || name == "surname" ||
name == "email" || name == "website")
{
cout << "element name: '" << name << "'"
<< ", text: '" << xml.readElementText()
<< "'" << endl;
}
}
}
if (xml.hasError())
{
cout << "XML error: " << xml.errorString() << endl;
}
else if (xml.atEnd())
{
cout << "Reached end, done" << endl;
}
回答by baysmith
The file is not UTF-8 encoded. Change the encoding to iso-8859-1 and it will parse without error.
该文件不是 UTF-8 编码的。将编码更改为iso-8859-1,它会正确解析。
<?xml version="1.0" encoding="iso-8859-1" ?>
回答by Frank Osterfeld
About the encoding: As baysmith and and hmuelner said, your file is probably incorrectly encoded (unless the encoding got lost when pasting it here). Try to fix that with some advanced text editor.
关于编码:正如 baysmith 和 hmuelner 所说,您的文件可能编码不正确(除非在此处粘贴时编码丢失)。尝试使用一些高级文本编辑器修复它。
The problem with your usage of text() is that it doesn't work as you expect it to. text() returns the content of the current token if it is of type Characters, Comment, DTD or EntityReference. Your current token is a StartElement, so it's empty. If you want to consume/read the text of the current startElement, use readElementText() instead.
您使用 text() 的问题在于它不像您期望的那样工作。如果当前标记的类型为 Characters、Comment、DTD 或 EntityReference,则 text() 返回当前标记的内容。您当前的令牌是一个 StartElement,所以它是空的。如果要使用/读取当前 startElement 的文本,请改用 readElementText()。
回答by hmuelner
Are you sure your document is UTF-8 encoded? What editor did you use? Check how the ?-characters look like if you view the file without decoding.
您确定您的文档是 UTF-8 编码的吗?你用的什么编辑器?如果您在没有解码的情况下查看文件,请检查 ? 字符的外观。
回答by Muhammad Suleman
Try this Example i just copied it from my project it work for me.
试试这个例子,我只是从我的项目中复制它,它对我有用。
void MainWindow::readXML(const QString &fileName)
{
fileName = "D:/read.xml";
QFile* file = new QFile(fileName);
if (!file->open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox::critical(this, "QXSRExample::ReadXMLFile", "Couldn't open xml file", QMessageBox::Ok);
return;
}
/* QXmlStreamReader takes any QIODevice. */
QXmlStreamReader xml(file);
/* We'll parse the XML until we reach end of it.*/
while(!xml.atEnd() && !xml.hasError())
{
/* Read next element.*/
QXmlStreamReader::TokenType token = xml.readNext();
/* If token is just StartDocument, we'll go to next.*/
if(token == QXmlStreamReader::StartDocument)
continue;
/* If token is StartElement, we'll see if we can read it.*/
if(token == QXmlStreamReader::StartElement) {
if(xml.name() == "email") {
ui->listWidget->addItem("Element: "+xml.name().toString());
continue;
}
}
}
/* Error handling. */
if(xml.hasError())
QMessageBox::critical(this, "QXSRExample::parseXML", xml.errorString(), QMessageBox::Ok);
//resets its internal state to the initial state.
xml.clear();
}
void MainWindow::writeXML(const QString &fileName)
{
fileName = "D:/write.xml";
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
QMessageBox::critical(this, "QXSRExample::WriteXMLFile", "Couldn't open anna.xml", QMessageBox::Ok);
return;
}
QXmlStreamWriter xmlWriter(&file);
xmlWriter.setAutoFormatting(true);
xmlWriter.writeStartDocument();
//add Elements
xmlWriter.writeStartElement("bookindex");
ui->listWidget->addItem("bookindex");
xmlWriter.writeStartElement("Suleman");
ui->listWidget->addItem("Suleman");
//write all elements in xml filexl
xmlWriter.writeEndDocument();
file.close();
if (file.error())
QMessageBox::critical(this, "QXSRExample::parseXML", file.errorString(), QMessageBox::Ok);
}