Emitting JSON with yaml-cpp?
Asked Answered
H

3

8

I'm using yaml-cpp on a for a variety of things on my project. Now I want to write out some data as JSON. Since JSON is a subset of YAML, at least for the features I need, I understand it should be possible to set some options in yaml-cpp to output pure JSON. How is that done?

Hashimoto answered 10/5, 2017 at 21:21 Comment(0)
L
5

yaml-cpp doesn't directly have a way to force JSON-compatible output, but you can probably emulate it.

YAML:Emitter Emitter;
emitter << YAML:: DoubleQuoted << YAML::Flow << /* rest of code */;
Leola answered 10/5, 2017 at 22:56 Comment(5)
That seems to work for my case, valid JSON is emitted. I just have one follow on question: The above results all the JSON being on one long line. Is there a way to also have it have newlines and indentation?Hashimoto
I don't think so.Leola
This does not seem to work anymore, or at least on more complex YAML. I get everything on different rows with YAML style arrays and objects when doing a complex << node output.Carrycarryall
Looks like this might be set on a per node basis? (flow vs no flow)Carrycarryall
this does not work if you have null value. yaml-cpp seems only use ~ as null, I cannot find a way to actually force it use nullWaikiki
G
2

Jesse Beder's answer didn't seem to work for me; I still got multiple lines of output with YAML syntax. However, I found that by adding << YAML::BeginSeq immediately after << YAML::Flow, you can force everything to end up on one line with JSON syntax. You then have to remove the beginning [ character:

YAML::Emitter emitter;
emitter << YAML::DoubleQuoted << YAML::Flow << YAML::BeginSeq << node;
std::string json(emitter.c_str() + 1);  // Remove beginning [ character

Here is a fully worked example.

There's still a major issue, though: numbers are quoted, turning them into strings. I'm not sure whether this is an intentional behavior of YAML::DoubleQuoted; looking at the tests, I didn't see any test case that covers what happens when you apply DoubleQuoted to a number. This issue has been filed here.

Gaskin answered 10/3, 2021 at 1:11 Comment(0)
T
0

All aforementioned answers didn't yield a proper json for non-trivial yaml files.

if you don't mind adding (or already have) nlohmann::json then, the following snippet by mircodz produces a valid json from a yaml node.

// Author: mircodz (Mirco De Zorzi)
// URL: https://github.com/mircodz/tojson/blob/master/tojson.hpp

inline nlohmann::json parse_scalar(const YAML::Node &node) {
  int i;
  double d;
  bool b;
  std::string s;

  if (YAML::convert<int>::decode(node, i))
    return i;
  if (YAML::convert<double>::decode(node, d))
    return d;
  if (YAML::convert<bool>::decode(node, b))
    return b;
  if (YAML::convert<std::string>::decode(node, s))
    return s;

  return nullptr;
}

inline nlohmann::json yaml2json(const YAML::Node &root) {
  nlohmann::json j{};

  switch (root.Type()) {
  case YAML::NodeType::Null:
    break;
  case YAML::NodeType::Scalar:
    return parse_scalar(root);
  case YAML::NodeType::Sequence:
    for (auto &&node : root)
      j.emplace_back(yaml2json(node));
    break;
  case YAML::NodeType::Map:
    for (auto &&it : root)
      j[it.first.as<std::string>()] = yaml2json(it.second);
    break;
  default:
    break;
  }
  return j;
}
Trachoma answered 21/9, 2024 at 0:26 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.