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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: [Решено] Потоковый разбор документа  (Прочитано 6980 раз)
vunder
Гость
« : Сентябрь 23, 2010, 11:43 »

По TCP получаю порциями xml-документы. Если размер небольшой, то приходит одной порцией, а если данных много, то несколько посылок.
Сначала использовать DOM-парсер, но при увеличении размера блока данных уже не мог им парсить. Почитал, что SAX-парсер (QXmlSimpleReader) позволяет работать с xml, постеменно обрабатывая данные через метод parse(xmlInput, true) и parseContinue(). Но возникла некоторая сложность: как с помошью SAX-парсера прочитать несколько документов в одном файле.
Например, данные такие:
Код
XML
<?xml version=\"1.0\" encoding=\"windows-1251\"?>
<tag>
 <elem a=\"1\" b=\"2\"/>
</tag>
<?xml version=\"1.0\" encoding=\"windows-1251\"?>
<tag>
 <elem2 d=\"101\" q=\"55.7\"/>
</tag>
При отправке такого блока QXmlSimpleReader получаю данные только первого блока. Как быть? Или все же придется переходить на QXmlStreamReader?
« Последнее редактирование: Сентябрь 25, 2010, 11:29 от vunder » Записан
deaks
Гость
« Ответ #1 : Сентябрь 23, 2010, 17:54 »

в xml-документе заголовок 1го уровня - то есть <?xml ?> может быть только один, следовательно и все QT-шные способы разбора (DOM, SAX) будут воспринимать только 1ый документ.

собственно выход у вас действительно один - QXmlStreamReader
 
Записан
vunder
Гость
« Ответ #2 : Сентябрь 24, 2010, 08:27 »

Попробовал QXMLStreamReader. Тоже не получилось. При чтении второго документа в блоке данных, генерит ошибку XML declaration not at start of document. Причем после этой ошибки при вызове мотода addData() метод atEnd() всегда возвращает true.
Записан
deaks
Гость
« Ответ #3 : Сентябрь 24, 2010, 09:26 »

хм...надо что-то придумать
все-таки в xml документе может быть только один родитель DOCUMENT

наверно если нельзя изменить входную структуру, то придется писать свой парсер под такие xml-ки
Записан
Alp
Гость
« Ответ #4 : Сентябрь 24, 2010, 11:00 »

Qt ориентирована на работу с well-formed xml-документами. А у тебя - он совсем не well-formed. Так что, думаю, стандартными средствами прочитать второй корневой элемент никак.
Записан
vunder
Гость
« Ответ #5 : Сентябрь 24, 2010, 16:35 »

Нашел решение.
При разборе запоминаю первый тэг в документе. Когда получаем QXmlStreamReader::EndElement этого тэга проверяем, совпадает ли текущая позиция анализатора с размером обрабатываемого блока. Если нет, значит в блоке находятся несколько домументов, поэтому сбрасываем состояние парсера, а остаток строки добавляем на обработку

Код
C++ (Qt)
void UnpProtocol::parseData(const QString &strXml)
{
   //adding buffer
   dataCount += strXml.length();
   xmlReader.addData(strXml);
   while (!xmlReader.atEnd())
   {
       xmlReader.readNext();
       if (!xmlReader.hasError())
       {
#ifdef QT_DEBUG
           qDebug() << xmlReader.tokenString() << "(" << xmlReader.tokenType() << ") "
                    << xmlReader.name().toString() << xmlReader.text();
#endif
           switch (xmlReader.tokenType())
           {
           case QXmlStreamReader::StartDocument:
               xmlDocStart = true; break;
           case QXmlStreamReader::EndDocument:
           {
               xmlDocStart = false;
               //if end of doc is not end of data
               if (xmlReader.characterOffset() != dataCount)
               {
                   //copy data from current pos to input
                   QString str = strXml.mid(strXml.length() - (dataCount - xmlReader.characterOffset())).trimmed();
                   xmlReader.clear();
                   dataCount = str.length();
                   if (dataCount > 0)
                       xmlReader.addData(str);
               }
               break;
           }
           case QXmlStreamReader::StartElement:
           {
               QString name = xmlReader.name().toString();
               if (xmlDocStart)
                   xmlStartTag = name;
               else
               {
                   //tag processig (...)
               }
               xmlDocStart = false;
               break;
           }
           case QXmlStreamReader::EndElement:
           {
               xmlDocStart = false;
               QString name = xmlReader.name().toString();
               if (name == xmlStartTag)
               {
                   //if end of doc is not end of data
                   if (xmlReader.characterOffset() != dataCount)
                   {
                       //copy data from current pos to input
                       QString str = strXml.mid(strXml.length() - (dataCount - xmlReader.characterOffset())).trimmed();
                       xmlReader.clear();
                       dataCount = str.length();
                       if (dataCount > 0)
                           xmlReader.addData(str);
                   }
               }
               break;
           }
           default: break;
           }
       } else
       {
#ifdef QT_DEBUG
           qDebug() << "parse error. " << xmlReader.errorString() << xmlReader.text();
#endif
       }
   }
   //if not parsing error then clearing reader state to parse new data block
   if (!xmlReader.hasError())
   {
       dataCount = 0;
       xmlReader.clear();
   }
}
 
Записан
EDJ
Гость
« Ответ #6 : Сентябрь 27, 2010, 21:28 »

В одном проекте тоже получал пачки xml-команд через tcp. Между командами мы с коллегами ставили разделитель, которого никогда не могло быть в самих данных - '\0' Подмигивающий
Записан
vunder
Гость
« Ответ #7 : Сентябрь 28, 2010, 08:55 »

В одном проекте тоже получал пачки xml-команд через tcp. Между командами мы с коллегами ставили разделитель, которого никогда не могло быть в самих данных - '\0' Подмигивающий
Тоже как вариант.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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