Почему функция XMLDocument :: FirstChild () TinyXML2 возвращает NULL при попытке проанализировать этот допустимый файл XML?

Я знаю, что, вероятно, мне здесь не хватает какой-то чрезвычайно очевидной вещи, но это сводит меня с ума уже несколько дней.

Вот простая функция, которую я написал, которая пока что должна найти первый тег в XML-документе:

void parse_weather_file(const char* weatherFileName, WeatherDataAsPWMValues *wd)
{
    if (wd == NULL) return;

    std::cout << weatherFileName << std::endl;

    tinyxml2::XMLDocument doc(weatherFileName);
    tinyxml2::XMLNode *root = doc.FirstChild();
    if (root == NULL) std::cout << "Error" << std::endl;
}

Вот XML-документ, который я пытаюсь разобрать:

<!-- Sample output of openWeatherMap API -->
<?xml version = "1.0" encoding = "utf-8"?>
<current>
    <city id = "2643741" name = "City of London">
        <coord lon = "-0.09" lat = "51.51">
        <country>GB</country>
    <sun rise = "2015-06-30T03:46:57" set = "2015-06-30T20:21:12">
    </city>
    <temperature value = "72.34" min = "66.2" max = "79.88" unit = "fahrenheit"/>
    <humidity value = "43" unit = "%">
    <pressure value = "1020" unit = "hPa">
    <wind>
        <speed value = "7.78" name = "Moderate breeze">
        <direction value = "140" code = "SE" name = "SouthEast">
    </wind>
    <clouds value = "0" name = "clear sky">
    <visibility value = "10000">
    <precipitation mode = "no">
    <weather number = "800" value = "Sky is Clear" icon = "01d">
    <lastupdate value = "2015-06-30T08:36:14">
</current>

И вот результат, который я получаю от функции:

test.xml
Error

Это предполагает, что root имеет значение NULL в конце функции, но я не уверен, почему это так.

Ваш XML не хорошо сформированный. У вас отсутствуют закрывающие косые черты на отдельных элементах. <lastupdate value = "2015-06-30T08:36:14">, например, должен быть <lastupdate value = "2015-06-30T08:36:14" /> (<- см. Индикатор самозакрывания /).

zx485 27.09.2018 20:51

@ zx485 Спасибо за ответ. К сожалению, эта ошибка все еще возникает даже с самозакрывающимися индикаторами на всех отдельных тегах.

Matt D 27.09.2018 20:56

Тогда ваш XML по-прежнему не правильно сформированный. Так что придется искать другие возможные ошибки. Я добавил ответ с версией хорошо сформированный вашего XML. Посмотрим, поможет ли это ...

zx485 27.09.2018 20:58

@ zx485 Эта ошибка по-прежнему возникает со следующим XML-файлом: <test><content>Hello, world</content></test>

Matt D 27.09.2018 21:03

См. stackoverflow.com/questions/43285461/… для обсуждения FirstChild() по сравнению с FirstChildElement().

stanthomas 28.09.2018 00:19
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
520
2

Ответы 2

Я сделал ваш XML хорошо сформированный, добавив закрывающий / для отдельных элементов. Вот как это выглядит:

<?xml version = "1.0" encoding = "utf-8"?>
<current>
    <city id = "2643741" name = "City of London">
        <coord lon = "-0.09" lat = "51.51" />
        <country>GB</country>
        <sun rise = "2015-06-30T03:46:57" set = "2015-06-30T20:21:12" />
    </city>
    <temperature value = "72.34" min = "66.2" max = "79.88" unit = "fahrenheit" />
    <humidity value = "43" unit = "%" />
    <pressure value = "1020" unit = "hPa" />
    <wind>
        <speed value = "7.78" name = "Moderate breeze" />
        <direction value = "140" code = "SE" name = "SouthEast" />
    </wind>
    <clouds value = "0" name = "clear sky" />
    <visibility value = "10000" />
    <precipitation mode = "no" />
    <weather number = "800" value = "Sky is Clear" icon = "01d" />
    <lastupdate value = "2015-06-30T08:36:14" />
</current>

Надеюсь, это поможет вам выявить ошибки ...

Как объяснил @ zx485, ваш XML искажен. Но даже после исправления ваш код все равно не сработает. Согласно Документация TinyXML-2, класс tinyxml2::XMLDocument НЕ имеет конструктора, который принимает имя файла в качестве входных данных. Однако у него есть конструктор, который принимает bool в качестве входных данных:

XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE );

const char* неявно конвертируется в bool, поэтому ваш код компилируется, но на самом деле вы вообще не загружаете файл, поэтому root имеет значение NULL.

Вместо этого вам нужно вызвать метод класса LoadFile():

XMLError LoadFile( const char* filename );

Например:

void parse_weather_file(const char* weatherFileName, WeatherDataAsPWMValues *wd)
{
    if (wd == NULL) return;

    std::cout << weatherFileName << std::endl;

    tinyxml2::XMLDocument doc;

    XMLError err = doc.LoadFile(weatherFileName);
    if (err != XML_SUCCESS) {
        std::cout << "Error loading file: " << (int)err << std::endl;

        /* or:

        std::cout << "Error loading file: " << doc.ErrorName() << std::endl;

        std::cout << "Error loading file: " << tinyxml2::XMLDocument::ErrorIDToName(err) << std::endl;

        std::cout << "Error loading file: " << doc.ErrorStr() << std::endl;

        std::cout << "Error loading file" <<< endl;
        doc.PrintError();

        */

        return;
    }

    tinyxml2::XMLNode *root = doc.FirstChild();
    if (root == NULL) {
        std::cout << "Error root is null" << std::endl;
        return;
    }

    // use root as needed...
}

Кроме того, вы должны использовать метод RootElement() вместо метода FirstChild():

tinyxml2::XMLElement *root = doc.RootElement();

Другие вопросы по теме