yaml-cpp icon indicating copy to clipboard operation
yaml-cpp copied to clipboard

Could you provide a method to dynamic access like this node("a","b","c",...)

Open littlebr369 opened this issue 2 years ago • 8 comments

As a user, sometimes we do not know how deep the yaml file will be. So it would be better if we can access the data like this YAML::Node node = YAML::LoadFile(file_path); T x = node("a","b","c",...).as<T>();

littlebr369 avatar May 16 '22 02:05 littlebr369

This makes it easier for users to encapsulate

littlebr369 avatar May 16 '22 03:05 littlebr369

What's wrong with a for loop?

jbeder avatar May 16 '22 03:05 jbeder

What's wrong with a for loop?

What I mean is that if I want to encapsulate codes like this:

template <class T, typename... Args> T GetField(Args... args){ std::vectorstd::string keys_container; for(auto &v:{args...}){ keys_container.push_back(v); } for(int i = 0; i < node_config.size(); i++){ YAML::Node new_config = node_config[i]; for (auto nitr = keys_container.begin(); nitr != keys_container.end(); nitr++){
if(new_config[*nitr]){ c = new_config[*nitr]; } } T x = new_config.as<T>(); return x;
}

It will failed because the refactor of "=" is quote like &. When change new_config, it will also change node_config which is not want to see. If I use Clone(), the run time is too long because the data copy. Thus, I do not know how to loop call []. Can you give me some advices? Or do you have any suggestions to achieve it in a proper way?

littlebr369 avatar May 17 '22 08:05 littlebr369

thank you so much

littlebr369 avatar May 17 '22 08:05 littlebr369

I am facing the same issue. use for loop to walk from root node to leaf node will cause the root node value changed.

bigcat26 avatar May 27 '22 07:05 bigcat26

What's wrong with a for loop?

What I mean is that if I want to encapsulate codes like this:

template <class T, typename... Args> T GetField(Args... args){ std::vectorstd::string keys_container; for(auto &v:{args...}){ keys_container.push_back(v); } for(int i = 0; i < node_config.size(); i++){ YAML::Node new_config = node_config[i]; for (auto nitr = keys_container.begin(); nitr != keys_container.end(); nitr++){ if(new_config[*nitr]){ c = new_config[*nitr]; } } T x = new_config.as(); return x; }

It will failed because the refactor of "=" is quote like &. When change new_config, it will also change node_config which is not want to see. If I use Clone(), the run time is too long because the data copy. Thus, I do not know how to loop call []. Can you give me some advices? Or do you have any suggestions to achieve it in a proper way?

the use of std::array inspired me. Here's my inelegant solution:

static inline std::vector<std::string> stringSplit(const std::string &str,
                                                   const char delimiter) {
  std::string tok;
  std::stringstream ss(str);
  std::vector<std::string> vec;
  while (std::getline(ss, tok, delimiter)) {
    vec.push_back(tok);
  }
  return vec;
}

static inline YAML::Node getNodeByPath(YAML::Node root,
                                       const std::string &path) {
  std::vector<YAML::Node> n{root};
  auto parts = stringSplit(path, '.');
  for (const auto &name : parts) {
    // std::string lower;
    // std::transform(part.begin(), part.end(), std::back_inserter(lower),
    //                tolower);
    auto child = n[n.size() - 1][name];
    if (child) {
        n.push_back(child);
        continue;
    }
    return child;
  }
  return n[n.size() - 1];
}

template <typename... Args>
static inline YAML::Node getNode(YAML::Node root, Args... args) {
  std::vector<YAML::Node> n{root};
  for (const auto &name : {args...}) {
    auto child = n[n.size() - 1][name];
    if (child) {
        n.push_back(child);
        continue;
    }
    return child;
  }
  return n[n.size() - 1];
}

TEST_CASE("parse", "[yaml]") {

  auto cfg = YAML::LoadFile("/home/chris/work/cxx/full.yml");

  auto nodeA = getNodeByPath(cfg, "root.certificate.ca");
  auto nodeB = getNodeByPath(cfg, "root.certificate.client");
  auto nodeC = getNode(cfg, "webcam", "cloud", "server");
  auto nodeD = getNode(cfg, "webcam", "database", "path");

  SPDLOG_INFO("cfg = {}", YAML::Dump(cfg));
  SPDLOG_INFO("nodeA = {}", YAML::Dump(nodeA));
  SPDLOG_INFO("nodeB = {}", YAML::Dump(nodeB));
  SPDLOG_INFO("nodeC = {}", YAML::Dump(nodeC));
  SPDLOG_INFO("nodeD = {}", YAML::Dump(nodeD));
}

bigcat26 avatar May 27 '22 08:05 bigcat26

I am facing the same issue. use for loop to walk from root node to leaf node will cause the root node value changed.

Have your problem solved?

littlebr369 avatar Jun 09 '22 06:06 littlebr369

I am facing the same issue. use for loop to walk from root node to leaf node will cause the root node value changed.

Have your problem solved?

I am using the code above as workaround.

bigcat26 avatar Jun 09 '22 10:06 bigcat26