Почему я не могу разобрать файл XML, используя QXmlStreamReader из Qt? - PullRequest
9 голосов
/ 17 ноября 2010

Я пытаюсь выяснить, как 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 example.xml
Запуск ... имя файла: example.xml
Файл открыт ОК
Кодировка:
Ошибка XML: Обнаруженонеправильно закодированный контент.

Что случилось?Этот файл не может быть проще и выглядит для меня непротиворечивым.С моим исходным файлом я также получаю пустую запись для кодировки, отображаются имена записей (), но, увы, текст () также пуст.Любые предложения очень ценятся, лично я глубоко озадачен.

Ответы [ 5 ]

11 голосов
/ 17 ноября 2010

Я отвечаю на это сам, так как эта проблема была связана с тремя проблемами, две из которых были подняты ответами.

  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;
}
4 голосов
/ 17 ноября 2010

Файл не в кодировке UTF-8.Измените кодировку на iso-8859-1, и она будет проанализирована без ошибок.

<?xml version="1.0" encoding="iso-8859-1" ?>
2 голосов
/ 17 ноября 2010

О кодировке: Как сказали Бэйсмит и Хмюлнер, ваш файл, вероятно, неправильно закодирован (если кодировка не потерялась при вставке его сюда).Попробуйте исправить это с помощью какого-нибудь продвинутого текстового редактора.

Проблема с использованием вами text () заключается в том, что он не работает так, как вы ожидаете.text () возвращает содержимое текущего токена, если он имеет тип Characters, Comment, DTD или EntityReference.Ваш текущий токен является StartElement, поэтому он пуст.Если вы хотите использовать / читать текст текущего startElement, используйте взамен readElementText ().

2 голосов
/ 17 ноября 2010

Вы уверены, что ваш документ в кодировке UTF-8?Какой редактор вы использовали?Проверьте, как выглядят символы ä, если вы просматриваете файл без декодирования.

1 голос
/ 03 апреля 2013

Попробуйте этот пример, я просто скопировал его из моего проекта, он работает для меня.

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


}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...