HowToEmitYAML

来源:互联网 发布:手机听书软件排行 编辑:程序博客网 时间:2024/05/01 05:52
This outlines the basic methods for emitting a YAML document.
Featured
Updated Sep 13, 2011 by jbe...@gmail.com

Contents

  • Basic Emitting
  • Simple Lists and Maps
  • Using Manipulators
  • STL Containers, and Other Overloads
  • Using Existing Nodes
  • Output Encoding
  • Lifetime of Manipulators
  • When Something Goes Wrong

Basic Emitting

The model for emitting YAML is std::ostream manipulators. A YAML::Emitter objects acts as an output stream, and its output can be retrieved through thec_str() function (as in std::string). For a simple example:

#include "yaml.h"int main(){   YAML::Emitter out;   out << "Hello, World!";      std::cout << "Here's the output YAML:\n" << out.c_str(); // prints "Hello, World!"   return 0;}

Simple Lists and Maps

A YAML::Emitter object acts as a state machine, and we use manipulators to move it between states. Here's a simple sequence:

YAML::Emitter out;out << YAML::BeginSeq;out << "eggs";out << "bread";out << "milk";out << YAML::EndSeq;

produces

- eggs- bread- milk

A simple map:

YAML::Emitter out;out << YAML::BeginMap;out << YAML::Key << "name";out << YAML::Value << "Ryan Braun";out << YAML::Key << "position";out << YAML::Value << "LF";out << YAML::EndMap;

produces

name: Ryan Braunposition: LF

These elements can, of course, be nested:

YAML::Emitter out;out << YAML::BeginMap;out << YAML::Key << "name";out << YAML::Value << "Barack Obama";out << YAML::Key << "children";out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq;out << YAML::EndMap;

produces

name: Barack Obamachildren:  - Sasha  - Malia

Using Manipulators

To deviate from standard formatting, you can use manipulators to modify the output format. For example,

YAML::Emitter out;out << YAML::Literal << "A\n B\n  C";

produces

|A B  C

and

YAML::Emitter out;out << YAML::Flow;out << YAML::BeginSeq << 2 << 3 << 5 << 7 << 11 < YAML::EndSeq;

produces

[2, 3, 5, 7, 11]

Comments act like manipulators:

YAML::Emitter out;out << YAML::BeginMap;out << YAML::Key << "method";out << YAML::Value << "least squares";out << YAML::Comment("should we change this method?");out << YAML::EndMap;

produces

method: least squares  # should we change this method?

And so do aliases/anchors:

YAML::Emitter out;out << YAML::BeginSeq;out << YAML::Anchor("fred");out << YAML::BeginMap;out << YAML::Key << "name" << YAML::Value << "Fred";out << YAML::Key << "age" << YAML::Value << "42";out << YAML::EndMap;out << YAML::Alias("fred");out << YAML::EndSeq;

produces

- &fred  name: Fred  age: 42- *fred

STL Containers, and Other Overloads

We overload operator << for std::vector, std::list, andstd::map, so you can write stuff like:

std::vector <int> squares;squares.push_back(1);squares.push_back(4);squares.push_back(9);squares.push_back(16);std::map <std::string, int> ages;ages["Daniel"] = 26;ages["Jesse"] = 24;YAML::Emitter out;out << YAML::BeginSeq;out << YAML::Flow << squares;out << ages;out << YAML::EndSeq;

to produce

- [1, 4, 9, 16]-  Daniel: 26  Jesse: 24

Of course, you can overload operator << for your own types:

struct Vec3 { int x; int y; int z; };YAML::Emitter& operator << (YAML::Emitter& out, const Vec3& v) {        out << YAML::Flow;        out << YAML::BeginSeq << v.x << v.y << v.z << YAML::EndSeq;        return out;}

and it'll play nicely with everything else.

Using Existing Nodes

We also overload operator << for YAML::Nodes, so you can output already-parsed nodes. Unfortunately, yaml-cpp does not yet provide a good way of modifying existing nodes, so currently the best way to do this is to use theEmitter and pick-and-choose from your node's children. For example:

YAML::Node node; // suppose this is a parsed map of scalars to scalars                 // and we want to replace the value of the key "foo" with "bar"YAML::Emitter emitter;emitter << YAML::BeginMap;for(YAML::Iterator it=node.begin();it!=node.end();++it) {   emitter << YAML::Key << it.first();   emitter << YAML::Value;   if(it.first().to<std::string>() == "foo")      emitter << "bar";   else      emitter << it.second();}emitter << YAML::EndMap;

It can get a bit unwieldy for more complex nodes, but it does the trick. Remember, though, that nodes retain no formatting (they represent data), so you may have to drill down to add what you want.

Output Encoding

The output is always UTF-8. By default, yaml-cpp will output as much as it can without escaping any characters. If you want to restrict the output to ASCII, use the manipulatorYAML::EscapeNonAscii:

emitter.SetOutputCharset(YAML::EscapeNonAscii);

Lifetime of Manipulators

Manipulators affect the next output item in the stream. If that item is aBeginSeq or BeginMap, the manipulator lasts until the correspondingEndSeq or EndMap. (However, within that sequence or map, you can override the manipulator locally, etc.; in effect, there's a "manipulator stack" behind the scenes.)

If you want to permanently change a setting, there are global setters corresponding to each manipulator, e.g.:

YAML::Emitter out;out.SetIndent(4);out.SetMapStyle(YAML::Flow);

When Something Goes Wrong

If something goes wrong when you're emitting a document, it must be something like forgetting aYAML::EndSeq, or a misplaced YAML::Key. In this case, emitting silently fails (no more output is emitted) and an error flag is set. For example:

   YAML::Emitter out;   assert(out.good());   out << YAML::Key;   assert(!out.good());   std::cout << "Emitter error: " << out.GetLastError() << "\n";
Comment by philippe...@gmail.com, Jun 18, 2009

In the following example:

std::vector <int> squares;squares.push_back(1);squares.push_back(4);squares.push_back(9);squares.push_back(16);std::map <std::string, int> ages;ages["Daniel"] = 26;ages["Jesse"] = 24;out << ages;YAML::Emitter out;out << YAML::BeginSeq;out << YAML::Flow << squares;out << ages;out << YAML::EndSeq;

You need to remove the 1st "out << ages;" for it to make sense with the output.