Russian Qt Forum
Июнь 17, 2024, 17:53 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: XML парсер  (Прочитано 12417 раз)
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;
}
« Последнее редактирование: Март 20, 2013, 16:37 от izhack » Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #1 : Март 07, 2013, 10:52 »

Добавьте вывод отладочных сообщений после выполнения readNextStartElement, readNext и т.п., чтобы посмотреть текущее имя элемента и тип токена. Тогда станет понятнее, в каком месте xml-файла находится парсер и что делать дальше.

Можно еще подумать, нужно ли парсить этот файл во внутренние структуры, или воспользоваться отображением всего файла в QDomDocument. Это зависит от поставленной задачи.
Записан

Пока сам не сделаешь...
izhack
Гость
« Ответ #2 : Март 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);
}
« Последнее редактирование: Март 20, 2013, 16:36 от izhack » Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #3 : Март 22, 2013, 10:37 »

Вроде понял в чем ошибка. Но не могу разобраться с алгоритмом обработки .xml файла QXmlStreamReader'ом.
В моём файле большая "вложенность" элементов. Поэтому парсер находит первый элемент, т.е.
...
и читает его. А остальные элементы он не видит, т.к. достиг конечного элемента.
Немного не так. Парсер, встречая открывающий или закрывающий тег, вызывает соответствующий обработчик. А ваша задача следить за уровнем вложенности и считывать выдаваемые им атрибуты.

Ранее я уже пытался найти способ упрощения работы с xml-документами с помощью sax - во вложении реализация этого способа в приложении к вашему случаю (Qt 5.0.1).

Более подробно можно почитать здесь: http://citforum.ru/internet/xml/objectview/. Правда, есть отличия в обработке текстовых элементов - я избавился от виртуального метода isTextElement. Собственно, меня ваш пример заинтересовал именно тем, что в у вас в текстовом элементе используются атрибуты. Я раньше на это не закладывался  Грустный, потом статью доработаю.

Объем кода примера вас не должен пугать - меняется только код xmldocs.cpp (реализация объектного представления документа bible.xml) и mainwindow.cpp (пример использования), остальное, т.е. cnode.cpp, cxmlreader.cpp - во всех проектах неизменно.

Кстати, можете оценить объем кода, рожденного C++Builder, с использованием dom (bible.cpp).
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
izhack
Гость
« Ответ #4 : Март 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();
   }
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #5 : Март 22, 2013, 11:18 »

А теперь представьте, что у вас не по 1 атрибуту в элементе, а по 100. И как все это будет работать?  Улыбающийся
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
izhack
Гость
« Ответ #6 : Март 22, 2013, 12:40 »

А теперь представьте, что у вас не по 1 атрибуту в элементе, а по 100. И как все это будет работать?  Улыбающийся
Согласен.
Поэтому читаю Ваш код. Улыбающийся
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.122 секунд. Запросов: 22.