Название: XML парсер
Отправлено: izhack от Март 06, 2013, 17:22
Есть .xml файлик: <?xml version="1.0"?> <XMLBIBLE biblename="Russian"> <BIBLEBOOK bname="Genesis"> <CHAPTER cnumber="1"> <VERS vnumber="1">In the beginning God created the heavens and the earth.</VERS> </CHAPTER> </BIBLEBOOK> </XMLBIBLE>
Не могу получить аттрибуты тега "BIBLEBOOK", зато аттрибуты "XMLBIBLE" считываются. QMap<QString, QString> Bible::parseBook(QXmlStreamReader& xml) { QMap<QString, QString> xmlbible; QXmlStreamAttributes attributes = xml.attributes(); if(xml.tokenType() != QXmlStreamReader::StartElement && xml.name() == "XMLBIBLE") { return xmlbible; } if(attributes.hasAttribute("biblename")) { xmlbible["biblename"] = attributes.value("biblename").toString(); } if(xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == "BIBLEBOOK") { if(attributes.hasAttribute("bname")) { xmlbible["bname"] = attributes.value("bname").toString(); } } xml.readNext(); while(!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == "XMLBIBLE")) { if(xml.tokenType() == QXmlStreamReader::StartElement) { /*название книги*/ if(xml.name() == "BIBLEBOOK") { this->addElementDataToMap(xml, xmlbible); } /*номер главы*/ if(xml.name() == "CHAPTER") { this->addElementDataToMap(xml, xmlbible); } /*номер текста*/ if(xml.name() == "VERS") { this->addElementDataToMap(xml, xmlbible); } } xml.readNext(); } return xmlbible; }
Название: Re: XML парсер
Отправлено: ViTech от Март 07, 2013, 10:52
Добавьте вывод отладочных сообщений после выполнения readNextStartElement, readNext и т.п., чтобы посмотреть текущее имя элемента и тип токена. Тогда станет понятнее, в каком месте xml-файла находится парсер и что делать дальше.
Можно еще подумать, нужно ли парсить этот файл во внутренние структуры, или воспользоваться отображением всего файла в QDomDocument. Это зависит от поставленной задачи.
Название: Re: XML парсер
Отправлено: izhack от Март 20, 2013, 16:33
Вроде понял в чем ошибка. Но не могу разобраться с алгоритмом обработки .xml файла QXmlStreamReader'ом. В моём файле большая "вложенность" элементов. Поэтому парсер находит первый элемент, т.е. XML <XMLBIBLE biblename="Russian">
, и его конечный элемент XML </XMLBIBLE>
. и читает его. А остальные элементы он не видит, т.к. достиг конечного элемента. Попытался выполнит такой цикл C++ (Qt) while(!(token == QXmlStreamReader::EndElement && xml.name() == "XMLBIBLE")) { if(token == QXmlStreamReader::StartElement && xml.name() == "XMLBIBLE") { books.append(this->parseBook(xml)); } xml.readNext(); }
для всех элементов. Он не работает. Как проверить, что для именно этого StartElement'а есть соответствующий ему EndElement, и парсер смог пробежаться по всем элементам? Вот класс parseXML() C++ (Qt) void Bible::parseXML() { QFile* file = new QFile("C:\\Users\\Adm\\Documents\\Visual Studio 2008\\Projects\\Project1\\Bible\\Win32\\Debug\\russian.xml"); if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox::critical(this, "Bible::parseXML", "Couldn't open russian.xml", QMessageBox::Ok); return; } QXmlStreamReader xml(file); QList< QMap<QString,QString> > books; while(!xml.atEnd() && !xml.hasError()) { QXmlStreamReader::TokenType token = xml.readNext(); if(token == QXmlStreamReader::StartDocument) { continue; } if(token == QXmlStreamReader::StartElement) { if(xml.name() == "XMLBIBLE") { books.append(this->parseBook(xml)); } if(xml.name() == "BIBLEBOOK") { books.append(this->parseBook(xml)); } if(xml.name() == "CHAPTER") { books.append(this->parseBook(xml)); } if(xml.name() == "VERS") { books.append(this->parseBook(xml)); } } } if(xml.hasError()) { QMessageBox::critical(this, "Bible::parseXML", xml.errorString(), QMessageBox::Ok); } xml.clear(); this->addBooksToUI(books); }
Название: Re: XML парсер
Отправлено: sergek от Март 22, 2013, 10:37
Вроде понял в чем ошибка. Но не могу разобраться с алгоритмом обработки .xml файла QXmlStreamReader'ом. В моём файле большая "вложенность" элементов. Поэтому парсер находит первый элемент, т.е. ... и читает его. А остальные элементы он не видит, т.к. достиг конечного элемента.
Немного не так. Парсер, встречая открывающий или закрывающий тег, вызывает соответствующий обработчик. А ваша задача следить за уровнем вложенности и считывать выдаваемые им атрибуты. Ранее я уже пытался найти способ упрощения работы с xml-документами с помощью sax - во вложении реализация этого способа в приложении к вашему случаю (Qt 5.0.1). Более подробно можно почитать здесь: http://citforum.ru/internet/xml/objectview/ (http://citforum.ru/internet/xml/objectview/). Правда, есть отличия в обработке текстовых элементов - я избавился от виртуального метода isTextElement. Собственно, меня ваш пример заинтересовал именно тем, что в у вас в текстовом элементе используются атрибуты. Я раньше на это не закладывался :(, потом статью доработаю. Объем кода примера вас не должен пугать - меняется только код xmldocs.cpp (реализация объектного представления документа bible.xml) и mainwindow.cpp (пример использования), остальное, т.е. cnode.cpp, cxmlreader.cpp - во всех проектах неизменно. Кстати, можете оценить объем кода, рожденного C++Builder, с использованием dom (bible.cpp).
Название: Re: XML парсер
Отправлено: izhack от Март 22, 2013, 11:10
Спасибо гигантское! Буду разбираться. Кстати удалось получить атрибуты, хоть и криво но всё же: C++ (Qt) while(!xml.atEnd()) { QXmlStreamReader::TokenType token = xml.readNext(); if(token == QXmlStreamReader::StartDocument) { continue; } if(token == QXmlStreamReader::StartElement) { QXmlStreamAttributes attributes = xml.attributes(); if(xml.name() == "XMLBIBLE") { if(attributes.hasAttribute("biblename")) { xmlbible["biblename"] = attributes.value("biblename").toString(); } } } if(token == QXmlStreamReader::StartElement) { QXmlStreamAttributes attributes = xml.attributes(); if(xml.name() == "BIBLEBOOK") { if (attributes.hasAttribute("bname")) { xmlbible["bname"] = attributes.value("bname").toString(); } } } if(token == QXmlStreamReader::StartElement) { QXmlStreamAttributes attributes = xml.attributes(); if(xml.name() == "CHAPTER") { if(attributes.hasAttribute("cnumber")) { xmlbible["cnumber"] = attributes.value("cnumber").toString(); } } } if(token == QXmlStreamReader::StartElement) { QXmlStreamAttributes attributes = xml.attributes(); if(xml.name() == "VERS") { if(attributes.hasAttribute("vnumber")) { xmlbible["vnumber"] = attributes.value("vnumber").toString(); } } } xml.readNext(); }
Название: Re: XML парсер
Отправлено: sergek от Март 22, 2013, 11:18
А теперь представьте, что у вас не по 1 атрибуту в элементе, а по 100. И как все это будет работать? :)
Название: Re: XML парсер
Отправлено: izhack от Март 22, 2013, 12:40
А теперь представьте, что у вас не по 1 атрибуту в элементе, а по 100. И как все это будет работать? :)
Согласен. Поэтому читаю Ваш код. :)
|