boost property_tree: перебирая атрибуты повторяющихся дочерних элементов внутри повторяющихся дочерних элементов

У меня есть следующий документ XML:

<root>
  <scenario name="ScenarioA">
    <param name="ParamA">1</param>
    <param name="ParamB">2</param>
    <param name="ParamC">3</param>
  </scenario>
  <scenario name="ScenarioB">
    <param name="ParamA">1</param>
    <param name="ParamB">2</param>
    <param name="ParamC">3</param>
  </scenario>
  <scenario name="ScenarioC">
    <param name="ParamA">1</param>
    <param name="ParamB">2</param>
    <param name="ParamC">3</param>
  </scenario>
</root>

С помощью boost::property_tree::ptreeЯ могу сделать следующее, чтобы перебрать элементы верхнего уровня:

ptree scenarioTree = myTree.get_child("root");
for (const auto& itr : scenarioTree) {
    if (itr.second.get<std::string>(<xmlattr>.name) == "ScenarioA") {
        // additional logic
    }
}

Я не могу получить какие-либо атрибуты тегов "param" для каждого сценария, используя тот же метод на itr.second:

ptree scenarioTree = myTree.get_child("root");
for (const auto& itr : scenarioTree) {
    if (itr.second.get<std::string>(<xmlattr>.name) == "ScenarioA") {
        ptree paramTree = itr.second;
        // Iterate through "param" tags
        for (const auto& paramItr: paramTree) {
            if (paramItr.second.get<std::string>(<xmlattr>.name) == "ParamA") {
                // doesn't exist
            }
        }
    }
}

Что я делаю неправильно? Моя теория заключается в том, что это проблема приведения между тем, что итератор ptree возвращает (self), и стандартным ptree, но я не уверен, как еще получить внутренние дочерние атрибуты. Я могу получить имена тегов param (через first) и значения параметров (через second.data()), только без атрибутов.

1 ответ

Решение

Атрибуты в дереве свойств добавляются как подузлы. Ниже узел можно перевести

  <scenario name="ScenarioA">
    <param name="ParamA">1</param>
    <param name="ParamB">2</param>
    <param name="ParamC">3</param>
  </scenario>

во что-то вроде этого:

  scenario 
     xmlattr.name   ScenarioA // this node doesn't have subnode with attribute name
     param 
       xmlattr.name  -> ParamA
     param 
       xmlattr.name  -> ParamB
     param 
       xmlattr.name  -> ParamC

Когда вы нашли сценарий с ScenarioA в качестве атрибута вы перебираете его дочерние элементы. Этот узел имеет 4 детей. Для каждого ребенка, которого вы хотите найти name атрибут, но один из них не имеет этого атрибута. метод get выдает исключение, когда путь не может быть найден. Вы можете перехватить это исключение или использовать значение по умолчанию:

boost::property_tree::ptree scenarioTree = pt.get_child("root");
for (const auto& itr : scenarioTree) 
{
    if (itr.second.get<std::string>("<xmlattr>.name") == "ScenarioA") 
    {
        boost::property_tree::ptree paramTree = itr.second;
        for (const auto& paramItr: paramTree) 
        {
            if (paramItr.second.get<std::string>("<xmlattr>.name","") == "ParamA") 
            {                                                    ^^^^ default value
                cout << "ParamA was found in ScenarioA" << endl;
            }
        }
    }
}

в результате я получил ParamA был найден в сценарии A.

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