【问题标题】:Why can't I parse a XML file using QXmlStreamReader from Qt?为什么我不能使用 Qt 中的 QXmlStreamReader 解析 XML 文件?
【发布时间】:2011-05-11 05:06:40
【问题描述】:

我正在尝试弄清楚 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>xmltest.exe 示例.xml
开始... 文件名:example.xml
文件打开正常
编码:
XML 错误:遇到错误编码的内容。

发生了什么?这个文件再简单不过了,而且对我来说看起来很一致。使用我的原始文件,我还得到了一个空白的编码条目,显示了条目的 names(),但可惜, text() 也是空的。任何建议都非常感谢,我个人非常困惑。

【问题讨论】:

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


    【解决方案1】:

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

    1. 该文件实际上不是 UTF-8 编码的。我将编码更改为 iso-8859-1,编码警告消失了。
    2. text() 函数无法按预期工作。我必须使用 readElementText() 来读取条目的内容。
    3. 当我尝试在不包含文本的元素上读取ElementText() 时,例如顶级 在我的例子中,解析器返回一个 "预期的字符数据" 错误,解析中断。我觉得这种行为很奇怪(我认为返回一个空字符串并继续会更好)但我想只要知道规范,我就可以解决它并避免在每个条目上调用此函数。

    按预期工作的相关代码部分现在如下所示:

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

    【讨论】:

    • 有趣。是的, readElementText() 通常有点错误。从数据可能不完整的流(例如套接字)增量读取数据时,它也无法正常工作,请参阅bugreports.qt.nokia.com/browse/QTBUG-14661
    • 我应该将此报告为错误吗?我不确定是不是这样,或者它是否应该那样工作。
    • @FrankOsterfeld readElementText() 有什么新东西吗?是否有任何功能可以检查它是否可以工作?
    【解决方案2】:

    文件不是 UTF-8 编码的。把编码改成iso-8859-1,解析就不会出错了。

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

    【讨论】:

    • 正确。我很惭愧我没有想到这一点。 :(
    • 但是如果没有指定 XML 编码呢? QXmlStreamReader 是否假定它是 UTF-8?即在 XML 文件的顶部有这个:&lt;mediawiki xmlns="http://www.mediawiki.org/xml/export-0.8/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.8/ http://www.mediawiki.org/xml/export-0.8.xsd" version="0.8" xml:lang="en"&gt; 给出 “遇到错误编码的内容。”
    【解决方案3】:

    关于编码:正如baysmith 和hmuelner 所说,您的文件可能编码不正确(除非在此处粘贴时编码丢失)。尝试使用一些高级文本编辑器来解决这个问题。

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

    【讨论】:

    • 我做了更多的研究,编码不为空,如果我在访问 encoding() 之前执行 readNext(),则显示为“UTF-8”。
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      试试这个例子,我刚刚从我的项目中复制了它,它对我有用。

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

      【讨论】:

        猜你喜欢
        • 2013-07-11
        • 1970-01-01
        • 2011-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-26
        • 1970-01-01
        • 2020-08-17
        相关资源
        最近更新 更多