Помогите распарсить XML

Тема в разделе "Arduino & Shields", создана пользователем AlexVS, 8 окт 2014.

  1. AlexVS

    AlexVS Гик

    Привет. Есть XML код, никак не могу найти общий алгоритм как распарсить его.
    Код (Text):
    <time day="2014-10-10">
    <symbol number="600" name="light snow" var="13d"/>
    <precipitation value="0.5" type="snow"/>
    <windDirection deg="253" code="WSW" name="West-southwest"/>
    <windSpeed mps="6.26" name="Moderate breeze"/>
    <temperature day="-1.13" min="-4.58" max="-1.13" night="-4.58" eve="-2.28" morn="-2.29"/>
    <pressure unit="hPa" value="1013.81"/>
    <humidity value="61" unit="%"/>
    <clouds value="overcast clouds" all="88" unit="%"/>
    </time>
    Нужно выделить:
    Day="2014-10-10"
    var="13d"
    value="0.5"; type="snow"
    code="WSW"
    mps="6.26"
    day="-1.13"; night="-4.58"
    value="1013.81"
    value="61"
    all="88"
     
  2. Megakoteyka

    Megakoteyka Оракул Модератор

    Сходу приходит в голову решение задачи "в лоб".
    Можно смастерить функцию, которая будет принимать имя узла и имя атрибута, а возвращать значение атрибута. Если структура документа не меняется, то должно прокатить.
    void GetValue(char* text, char* nodeName, char* attrName, char* result);

    Алгоритм может быть таким: найти в тексте первое вхождение имени узла; начиная поиск с найденной позиции найти первое вхождение имени атрибута (можно еще контролировать, что до нахождения имени атрибута не должен встретиться символ '>'); начиная поиск с позиции атрибута найти первую и вторую кавычку и вытащить то, что находится между ними; в случае неудачного поиска на любом шаге вернуть NULL.
    Функцию нужно будет вызвать для каждого атрибута с соответствующими параметрами.
    char Day[11];
    GetValue(text, "time", "day", Day);

    Такого алгоритма будет достаточно?
     
  3. AlexVS

    AlexVS Гик

    Общая идея мне понятна, однако приведенный выше XML на момент обработки имеется не в полном виде, а вычитывается из клиента побайтно.
    Код (Text):
        while (!client.available());
            while (client.available()) {ReadByte();}
        }
    .....
    void ReadByte()
    {
        char inChar = client.read();
    // Обработка //
    }
     
    Структура документа постоянна.
     
  4. Megakoteyka

    Megakoteyka Оракул Модератор

    Можно же сначала целиком прочитать документ и затем подать его на вход парсера.
    Либо принимать отдельно каждый узел, это сэкономит память.
     
  5. Unixon

    Unixon Оракул Модератор

    ТС, а конечный автомат для разбора написать не по силам?
     
  6. AlexVS

    AlexVS Гик

    Принять документ - памяти не хватит, на узел - тоже, а вот строку наверное можно попробовать.
    На Си, к сожалению пока что нет.
     
  7. Unixon

    Unixon Оракул Модератор

    Эх, жаль. Но это не так сложно, как кажется. Вы просто объявляете количество состояний, равное количеству синтаксических элементов, потом внутри каждого состояния проверяете каждый новый символ на соответствие алфавиту этого элемента или шаблону, при этом накапливаете символы в строке (буфере), как только встречаете несоответствие - переходите к следующему элементу. Так исходный поток разбивается на токены, а уж из них вытащить данные - плевое дело. Собственно, разбор частично повторяется еще раз, но вместо отдельных символов вы уже работаете с элементами XML.
     
  8. Unixon

    Unixon Оракул Модератор

    Ну т.е. сначала ищите во входном потоке начало тэга "<". Если нашли - переходите к считыванию имени тэга, как только встретился пробел - все, начинаете распознавать аргументы, точно так же, ключ, "=", значение. Если встречаете ">" или "/>" переходите на чтение ветви DOM или к следующему узлу этого же уровня и т.д.

    Т.к. весь текст в памяти не хранится - данные извлекаете сразу как будет обнаружена тройка токенов "ключ", "=", "значение", идущих подряд.
     
    ИгорьК нравится это.
  9. AlexVS

    AlexVS Гик

    Можно хотя бы небольшой кусочек кода в качестве наглядного примера?
     
  10. KamAdm

    KamAdm Нерд

    А на каком языке программирования нужно это сделать?
    Это должен делать ардуин или комп?
     
  11. AlexVS

    AlexVS Гик

    Ардуино и соответственно Срр
     
  12. AlexVS

    AlexVS Гик

    Не могу найти в библиотеках функцию strtof ? Она есть в ардуиновской IDE?
     
  13. ИгорьК

    ИгорьК Гуру

    В библиотеке <stdlib.h> есть функция double atof(const char* nptr). Может подойдет? Потому как strtof сидит в той же библиотеке, но вот в AVR ее нет.
     
    Последнее редактирование: 13 окт 2014
  14. AlexVS

    AlexVS Гик

    Похоже, что ТО что нужно. Вечером попробую. Спасибо.
    В общем написал я парсер. Изначально воспользовался алгоритмом разборщика XML из интернета http://forum.arduino.cc/index.php/topic,39023.0.html , с его помощью я накапливаю содержимое 1 строки в массив, после чего разбираю строку с помощью объекта String.
     
  15. KamAdm

    KamAdm Нерд

  16. AlexVS

    AlexVS Гик

    По моему это для противоположного действия, формирования XML.
     
  17. KamAdm

    KamAdm Нерд

    Упс! Не внимателен.
     
  18. AlexVS

    AlexVS Гик

    Ну вот, все работает как надо. Всем спасибо за советы и идеи!
    Осталось только строки:
    sun rise: 2014-10-14T00:18:33
    sun set: 2014-10-14T10:51:01
    перевести в дату и время. Информацию о восходе хочу использовать для корректировки показаний уличного датчика температуры, т.к. он на солнечной стороне висит.