2010-11-17 106 views
9

我想弄清楚QXmlStreamReader如何为我写的C++应用程序工作。我想解析的XML文件是一个庞大的词典,它具有复杂的结构和大量的Unicode字符,所以我决定用一个更简单的文档来尝试一个小的测试用例。不幸的是,我撞墙了。下面是示例XML文件:为什么我无法使用Qt中的QXmlStreamReader解析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> 

...我试图用这个代码解析它:

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 example.xml
Starting... filename: example.xml
File opened OK
Encoding:
XML error: Encountered incorrectly encoded content.

发生了什么事?这个文件不能简单一些,它看起来与我一致。用我的原始文件,我也得到一个空白条目的编码,条目的名称()显示,但唉,文本()也是空的。任何建议非常感谢,我个人觉得神秘莫测。

回答

11

我回答这个问题我自己,因为这问题涉及到三个问题,其中两个是由反应长大。

  1. 该文件实际上不是UTF-8编码。我将编码更改为iso-8859-1,编码警告消失。如我所料
  2. 文本()功能不起作用。我必须使用readElementText()来读取条目的内容。
  3. 当我尝试readElementText()不包含文本,像顶级 <人>在我的案件的元素,解析器返回“预期的字符数据”错误和语法分析中断。我发现这种行为很奇怪(在我看来,返回一个空字符串,并继续会更好),但我猜只要规范已知,我可以解决它,并避免在每个条目上调用此函数。

相关的代码段为目前预计的作品看起来是这样的:

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

有趣的是,readElementText()总体上有点bug,在增量读取数据时也不起作用从数据可能不完整的流(例如套接字),请参阅http://bugreports.qt.nokia.com/browse/QTBUG-14661 – 2010-11-17 17:55:36

+0

我应该将此报告为错误吗?我不确定它是否可以是,还是如果它应该这样工作。 – neuviemeporte 2010-11-17 22:06:12

+0

@FrankOsterfeld在'readElementText()'上有什么新东西?是否有任何功能来检查它是否会工作? – Niklas 2014-07-08 23:48:21

2

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

4

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

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

权上。我很惭愧,我没有想到这一点。:( – neuviemeporte 2010-11-17 16:07:58

+0

但是如果没有指定XML编码呢?QXmlStreamReader是否认为它是UTF-8?即:'在XML文件的顶部给出**”遇到错误编码的内容。“** – bitek 2013-07-10 08:11:47

2

关于编码:作为baysmith和和hmuelner说,你的文件可能是不正确的编码(除非在此粘贴时,它的编码迷路了)。尝试使用一些高级文本编辑器修复这个问题。

与文本的使用()的问题是,当你希望它这是行不通的。如果字符,注释,DTD或EntityReference类型,则text()会返回当前标记的内容。你当前的标记是一个StartElement,所以它是空的。如果要使用/读取当前startElement的文本,请改为使用readElementText()。

+0

我做了一些更多的研究和编码不是空的,如果我在访问encoding()之前做一个readNext(),就会出现“UTF-8” – neuviemeporte 2010-11-17 12:42:52

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


} 
相关问题