user9635643
user9635643

Reputation: 11

How to return sequences in YAML node as string?

I'm trying to parse a dialogue tree (YAML) in C++ using yaml-cpp. Here's a sample YAML:

dialogue_block:
  character_name:
    - Hello
    - How are you?
    - :main
main:
  - 1: ["I'm fine, thank you", :response1]
  - 2: ["Not very well", :response2]
  - 3: ["I don't want to talk", :exit]

I'm relatively new to C++ and Yaml, so if there's an easier/more intuitive way, please point me in the right direction. My idea is to store each block as a dialogue node. In the example above, I want to be able to call on dialogue_block, and extract character_name to identify the character speaking, print all of the sequences up to :main, where it'll switch to the main node, with 3 choices for the player. I'm currently stuck on step 1 - parsing the yaml file...

The following works...

YAML::Node dialogue = YAML::LoadFile("dialogue.yaml");
if(dialogue["dialogue_block"]){
  std::cout << dialogue["dialogue_block"]["character_name"][0].as<std::string>() << "\n";
}

and it prints "Hello". However, I'm stumped on the next steps: how can I retrieve "character_name" without hardcoding the string into my code? Is there a way to print all of the strings leading up to, but not including ":main"? And then make "main" the next node?

First time posting on stackoverflow, so please do let me know if there's more info needed! Thanks.

Edit: Here's the updated code I'm using:

// read in file
YAML::Node dialogue = YAML::LoadFile("dialogue.yaml");

// Extract names of each block
std::vector<std::string> dialogueBlocks;
for (const auto& kv : dialogue) {
    dialogueBlocks.push_back(kv.first.as<std::string>());
} // will return "dialogue_block" and "main" 

std::string character;

// if first_encounter exists, always start at that block
if(dialogue["first_encounter"]){
    for(YAML::iterator it = dialogue["first_encounter"].begin(); it != dialogue["first_encounter"].end(); ++it){
        character = it->first.as<std::string>();
        std::cout << "\nCharacter: " << character << "\n";
        for (YAML::iterator it=dialogue["first_encounter"][character].begin();it!=dialogue["first_encounter"][character].end(); ++it) {
        std::cout << it->as<std::string>() << "\n";
    }
    }

}

I can successfully extract the character name and the dialogue, but there are a few things I'm struggling with: 1) It also prints ":main", which I want it to leave out. I'm not sure how to get it to terminate when it reaches a string starting with ":", or if there's an appropriate built-in function to use. 2) Store ":main" as the next block to pass through the for loop when called upon.

Upvotes: 1

Views: 2909

Answers (1)

Rob Starling
Rob Starling

Reputation: 3908

You're asking how to find the "key name" for the list. You could certainly look at all the keys under dialogue["dialogue_block"], but it would be much more idiomatic yaml to make character a separate field from their lines, like so

dialogue_block:
  character: Bob
  lines:
    - Hello
    - How are you?
    - :main

or if a block is intended to be a list,

dialogue_block:
  - character: Bob
    lines:
      - Hello
      - How are you?
      - :main
  - character: Alice
    lines:
      - Blah
      - :main

Upvotes: 0

Related Questions