Чтение массива значений из XML с Boost.PropertyTree - PullRequest
0 голосов
/ 24 мая 2019

У меня есть пример XML-файла:

<?xml version="1.0" ?>
<Root>
  <ChildArray>
    1.0  0.0 -1.0
  </ChildArray>
</Root>

Я пытаюсь прочитать его с помощью Boost.PropertyTree, пытаясь выполнить следующее:

#include <array>
#include <string>
#include <iostream>
#include <exception>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

namespace pt = boost::property_tree;

struct VectorXML
{
    std::array<float, 3> _data;
    void load(const std::string &filename);
};

void VectorXML::load(const std::string &filename)
{
    // Create empty property tree object
    pt::ptree tree;

    // Parse the XML into the property tree.
    pt::read_xml(filename, tree);

    _data=
        tree.get<std::array<float, 3>>("Root.ChildArray");
}

int main()
{
    try
    {
        VectorXML v;
        v.load("data.xml");
        std::cout << "Success\n";
        std::cout
            << "X: " << v._data[0] << " "
            << "Y: " << v._data[1] << " "
            << "Z: " << v._data[2] << "\n";
    }
    catch (std::exception &e)
    {
        std::cout << "Error: " << e.what() << "\n";
    }
    return 0;
}

Но он не компилируется (>> перегрузка в stream_translator.hpp не принимает std::array с).

Полагаю, мне придется вручную перебирать данные, но я не могу найти способ извлечения данных из этого узла, документация не ясна о том, как получить доступ к данным в узлах с более чем 1 значением. .

Что-то вроде

for (size_t i = 0; i < 3; ++i)
    _data[i] = tree.get<float>("Root.ChildMatrix.???");

Но это не работает (узел имеет 3 числа с плавающей запятой, и boost не может преобразоваться в "число с плавающей запятой").

1 Ответ

0 голосов
/ 24 мая 2019

Ладно, это было легко, и я идиот, потому что я не стараюсь больше.Я не буду отмечать это как ответ в случае, если кто-то публикует лучший ответ.

Я расширил ответ, чтобы приспособить матрицы любого измерения (предполагается, что вы добавляете атрибут Size="M N" к узлу).

Ответ на оригинальный вопрос

std::stringstream iss(
    tree.get_child("Root.ChildArray")
        .data() // string
);
float number = 0;
for (size_t i = 0; i < 3; i++)
    if (iss >> number)
        _data[i] = number;

Расширенный ответ

Здесь я добавляю проверку атрибута для чтения измерений (обратите внимание, что это можно улучшить, особенно для большего количества измерений, и этокаждый по-прежнему использует array<float,3> вместо полностью динамического контейнера).

// probably can be done in a more elegant way
std::stringstream iss(
    tree.get<std::string>("Root.ChildArray.<xmlattr>.Dimensions")
);
size_t M = 0;
iss >> M;
// *********
iss.str(
    tree.get_child("Root.ChildArray")
        .data()
);
_data.resize(M);
float number = 0;
for (size_t row = 0; row < M; row++)
{
    for (size_t col = 0; col < 3; col++)
    {
        if (iss >> number)
        {
            _data[row][col] = number;
        }
    }
}

Попробуйте использовать следующий XML:

<?xml version="1.0" ?>
<Root>
  <ChildArray Dimensions="2 3">
    1.0  0.0 -1.0
    0.0  0.4  1.0
  </ChildArray>
</Root>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...