2010-11-17 68 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); 


} 
相關問題