oohshiny
oohshiny

Reputation: 13

Yaml-cpp: Disable automatic begindoc (---) before each new map in emitter

I'm using yaml-cpp to generate a structure log file that I can read back in again later. It might not be the best tool for the job, but right now I just need something to get started with.

However, I've hit a bit of a problem, as this example output shows:

---
0: 42
---
1: 42
---
2: 42
---
3: 42
---
4: 42
...

What I wanted was this:

---
0: 42
1: 42
2: 42
3: 42
4: 42
...

This is the code that generated it:

YAML::Emitter res;
res << YAML::BeginDoc;
for (int i = 0; i < 5; i++)
{
    res << YAML::BeginMap
        << YAML::Key << i
        << YAML::Value << 42
        << YAML::EndMap;
}
res << YAML::EndDoc;
std::cout << res.c_str() << std::endl;

I looked at the source (https://github.com/jbeder/yaml-cpp/blob/master/src/emitter.cpp) and found this bit:

// EmitBeginDoc
void Emitter::EmitBeginDoc() {
  if (!good())
    return;

  if (m_pState->CurGroupType() != GroupType::NoType) {
    m_pState->SetError("Unexpected begin document");
    return;
  }

  if (m_pState->HasAnchor() || m_pState->HasTag()) {
    m_pState->SetError("Unexpected begin document");
    return;
  }

  if (m_stream.col() > 0)
    m_stream << "\n";
  m_stream << "---\n";

  m_pState->StartedDoc();
}

but what I do from here is beyond me. On one hand, I could make a small hack and just remove all --- from the output before I write it to a file (except the first one, of course), but on the other hand I just assume that I must have overlooked some detail that will solve this issue more elegantly.

Edit: My example doesn't justify a map, so I'll explain a bit further. I'm storing some meta information for a large collection of images. When I read them back in, I would like to access the information for each image directly, i.e. myyaml[frame_id]["algorithm_2"]["result_x"] where frame_id could be e.g. 3. I don't know how to do this if each image has its own document in the file, short of iterating through the entire file for every lookup. The images are not necessarily in an unbroken sequence from 0 to number_of_images.

Edit 2: In reference to the edited answer by João Augusto here's a more elaborate example which also doesn't work:

YAML::Emitter res;
res << YAML::BeginDoc;
for (int i = 3; i < 7; i++)
{
    res << YAML::BeginMap
        << YAML::Key << i
        << YAML::Value
            << YAML::BeginSeq
            << YAML::BeginMap
                << YAML::Key << "Algorithm 1"
                << YAML::Value
                << YAML::BeginSeq
                    << YAML::Flow
                    << YAML::BeginSeq << 54*i << 42/i << 10+i << 17-i << YAML::EndSeq
                    << YAML::Flow
                    << YAML::BeginSeq << 6*i << 3/i << 87+i << 33-i << YAML::EndSeq
                << YAML::EndSeq
            << YAML::EndMap
            << YAML::BeginMap
                << YAML::Key << "Algorithm 2"
                << YAML::Value
                << YAML::BeginSeq
                    << YAML::Flow
                    << YAML::BeginSeq << 65*i << 27/i << 54+i << 76-i << YAML::EndSeq
                    << YAML::Flow
                    << YAML::BeginSeq << 45*i << 66/i << 98+i << 34-i << YAML::EndSeq
                << YAML::EndSeq
            << YAML::EndMap
            << YAML::EndSeq
        << YAML::EndMap;
}
res << YAML::EndDoc;
std::cout << res.c_str() << std::endl;

This is the output:

---
3:
  - Algorithm 1:
      - [162, 14, 13, 14]
      - [18, 1, 90, 30]
  - Algorithm 2:
      - [195, 9, 57, 73]
      - [135, 22, 101, 31]
---
4:
  - Algorithm 1:
      - [216, 10, 14, 13]
      - [24, 0, 91, 29]
  - Algorithm 2:
      - [260, 6, 58, 72]
      - [180, 16, 102, 30]
---
5:
  - Algorithm 1:
      - [270, 8, 15, 12]
      - [30, 0, 92, 28]
  - Algorithm 2:
      - [325, 5, 59, 71]
      - [225, 13, 103, 29]
---
6:
  - Algorithm 1:
      - [324, 7, 16, 11]
      - [36, 0, 93, 27]
  - Algorithm 2:
      - [390, 4, 60, 70]
      - [270, 11, 104, 28]
...

which still has the unwanted new document statements. What do I need to change in my code to make them not appear?

Upvotes: 1

Views: 306

Answers (1)

Jo&#227;o Augusto
Jo&#227;o Augusto

Reputation: 2305

You should read the docs of the yaml format. You are creating a map for each item, what you want is something like this.

YAML::Emitter res;
res << YAML::BeginDoc << YAML::BeginMap;
for (int i = 0; i < 5; i++)
{
    res << YAML::Key << i
        << YAML::Value << 42;

}
res << YAML::EndMap << YAML::EndDoc;

Edit...

You just need to write the yaml in the way you want to access the data, so if you do something like this:

---
frame_0:
  algorithm_1: 1
  algorithm_2: 2
frame_1:
  algorithm_1: 10
  algorithm_2: 2
frame_2:
  algorithm_1: 8
  algorithm_2: 22
frame_3:
  algorithm_1: 1
  algorithm_2: 23
frame_4:
  algorithm_1: 12
  algorithm_2: 21
...

You can access for example the value of algorithm_2 in frame_3 by doing this:

YAML::Node yaml = YAML::Load(res.c_str());
int value = yaml["frame_3"]["algorithm_2"].as<int>();

Edit...

YAML::Emitter res;
res << YAML::BeginDoc;
res << YAML::BeginMap;
for (int i = 3; i < 7; i++)
{

    res << YAML::Key << i
        << YAML::Value
        << YAML::BeginSeq
        << YAML::BeginMap
        << YAML::Key << "Algorithm 1"
        << YAML::Value
        << YAML::BeginSeq
        << YAML::Flow
        << YAML::BeginSeq << 54 * i << 42 / i << 10 + i << 17 - i << YAML::EndSeq
        << YAML::Flow
        << YAML::BeginSeq << 6 * i << 3 / i << 87 + i << 33 - i << YAML::EndSeq
        << YAML::EndSeq
        << YAML::EndMap
        << YAML::BeginMap
        << YAML::Key << "Algorithm 2"
        << YAML::Value
        << YAML::BeginSeq
        << YAML::Flow
        << YAML::BeginSeq << 65 * i << 27 / i << 54 + i << 76 - i << YAML::EndSeq
        << YAML::Flow
        << YAML::BeginSeq << 45 * i << 66 / i << 98 + i << 34 - i << YAML::EndSeq
        << YAML::EndSeq
        << YAML::EndMap
        << YAML::EndSeq;
}
res << YAML::EndMap;
res << YAML::EndDoc;

This will do what you want, your problem is that (assuming you want a map with the keys from 3 to 7) you are creating a map for 3, 4, 5, 6 and 7 instead of having a map with the keys 3,4,...,7

Upvotes: 1

Related Questions