为什么我不能使用Qt的QXmlStreamReader解析XML文件?

时间:2010-11-17 03:19:47

标签: c++ xml qt qt4 xml-parsing

我正在试图弄清楚QXmlStreamReader如何为我正在编写的C ++应用程序工作。我要解析的XML文件是一个大字典,结构复杂,有很多Unicode字符,所以我决定尝试一个带有更简单文档的小测试用例。不幸的是,我碰壁了。这是示例xml文件:

<?xml version="1.0" encoding="UTF-8" ?>
<persons>
    <person>
        <firstname>John</firstname>
        <surname>Doe</surname>
        <email>john.doe@example.com</email>
        <website>http://en.wikipedia.org/wiki/John_Doe</website>
    </person>
    <person>
        <firstname>Jane</firstname>
        <surname>Doe</surname>
        <email>jane.doe@example.com</email>
        <website>http://en.wikipedia.org/wiki/John_Doe</website>
    </person>
    <person>
        <firstname>Matti</firstname>
        <surname>Meikäläinen</surname>
        <email>matti.meikalainen@example.com</email>
        <website>http://fi.wikipedia.org/wiki/Matti_Meikäläinen</website>
    </person>
</persons>

...我正在尝试使用此代码解析它:

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;
}

...然后我得到了这个输出:

  

C:\ xmltest \ Debug&gt; xmltest.exe example.xml
  正在启动... filename:example.xml
  文件打开OK   编码:
  XML错误:遇到编码错误的内容。

发生什么事了?这个文件不能简单,看起来和我一致。使用我的原始文件,我也得到一个空白的编码条目,显示条目的名称(),但是,唉,text()也是空的。任何建议都非常感谢,个人而言,我是彻底的神秘化。

5 个答案:

答案 0 :(得分:11)

我自己也在回答这个问题,因为这个问题与三个问题有关,其中两个问题是由答复提出来的。

  1. 该文件实际上不是UTF-8编码的。我将编码更改为iso-8859-1,编码警告消失了。
  2. text()函数无法正常工作。我必须使用readElementText()来读取条目的内容。
  3. 当我尝试在不包含文本的元素上读取元素文本()时,例如我的情况下的顶级&lt; persons&gt; ,解析器返回“预期字符数据“错误,解析中断。我发现这种行为很奇怪(在我看来,返回一个空字符串并继续会更好)但我想只要规范已知,我就可以解决它并避免在每个条目上调用此函数。
  4. 现在按预期工作的相关代码部分如下所示:

    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;
    }
    

答案 1 :(得分:4)

该文件不是UTF-8编码的。将编码更改为iso-8859-1,它将无错误地解析。

<?xml version="1.0" encoding="iso-8859-1" ?>

答案 2 :(得分:2)

您确定您的文档是UTF-8编码的吗?你用了什么编辑器?如果您在不解码的情况下查看文件,请检查ä字符的外观。

答案 3 :(得分:2)

关于编码:正如baysmith和hmuelner所说,你的文件可能编码不正确(除非编码在这里粘贴时丢失了)。尝试使用一些高级文本编辑器修复它。

使用text()的问题在于它无法正常工作。如果当前标记的类型为Characters,Comment,DTD或EntityReference,则text()返回当前标记的内容。您当前的令牌是StartElement,因此它是空的。如果要使用/读取当前startElement的文本,请改用readElementText()。

答案 4 :(得分:1)

试试这个例子我只是从我的项目中复制它对我有用。

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);


}