LibYAML涵盖了演示和解析过程。 因此,LibYAML定义了以下两个处理器:
- 解析器,其接收字节的输入流并产生解析事件序列。
- 发射器,它接收一系列事件并产生一串字节。
The processes of parsing and presenting are inverse to each other. Any sequence of events produced by parsing a well-formed YAML document should be acceptable by the Emitter, which should produce an equivalent document. Similarly, any document produced by emitting a sequence of events should be acceptable for the Parser, which should produce an equivalent sequence of events.
解析和演示的过程彼此相反。 通过分析格式良好的YAML文档所产生的任何事件序列应由发射器接受,该发射器应该产生等效的文件。 类似地,通过发出一系列事件而产生的任何文档应该被解析器所接收,该解析器应该产生等效的事件序列。
事件类型
STREAM-START
STREAM-END
DOCUMENT-START
DOCUMENT-END
ALIAS
SCALAR
SEQUENCE-START
SEQUENCE-END
MAPPING-START
MAPPING-END
#include "yaml.h"
#include
#include
#include
#include
// our data models
struct Vec3
{
float x, y, z;
};
struct Power
{
std::string name;
int damage;
};
struct Monster
{
std::string name;
Vec3 position;
std::vector powers;
};
// operators for parsing
void operator >> (const YAML::Node& node, Vec3& v)
{
node[0] >> v.x;
node[1] >> v.y;
node[2] >> v.z;
}
void operator >> (const YAML::Node& node, Power& power)
{
node["name"] >> power.name;
node["damage"] >> power.damage;
}
void operator >> (const YAML::Node& node, Monster& monster)
{
node["name"] >> monster.name;
node["position"] >> monster.position;
const YAML::Node& powers = node["powers"];
for(unsigned i = 0; i < powers.size(); i++)
{
Power power;
powers[i] >> power;
monster.powers.push_back(power);
}
}
// operators for emitting
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;
}
YAML::Emitter& operator << (YAML::Emitter& out, const Power& power)
{
out << YAML::BeginMap;
out << YAML::Key << "name";
out << YAML::Value << power.name;
out << YAML::Key << "damage";
out << YAML::Value << power.damage;
out << YAML::EndMap;
return out;
}
YAML::Emitter& operator << (YAML::Emitter& out, const Monster& monster)
{
out << YAML::BeginMap;
out << YAML::Key << "name";
out << YAML::Value << monster.name;
out << YAML::Key << "position";
out << YAML::Value << monster.position;
out << YAML::Key << "powers";
out << YAML::Value;
out << YAML::BeginSeq;
for(size_t pidx = 0; pidx < monster.powers.size(); ++pidx)
{
out << monster.powers[pidx];
}
out << YAML::EndSeq;
out << YAML::EndMap;
return out;
}
int main()
{
std::string monsters_yaml("- name: Ogre\n position: [0, 5, 0]\n powers:\n - name: Club\n damage: 10\n - name: Fist\n damage: 8\n- name: Dragon\n position: [1, 0, 10]\n powers:\n - name: Fire Breath\n damage: 25\n - name: Claws\n damage: 15\n- name: Wizard\n position: [5, -3, 0]\n powers:\n - name: Acid Rain\n damage: 50\n - name: Staff\n damage: 3\n");
// list of monsters
std::vector monsters;
// write out the monster.yaml
std::ofstream monsters_yaml_file;
monsters_yaml_file.open("monsters.yaml");
monsters_yaml_file << monsters_yaml;
monsters_yaml_file.close();
// read in the the monster.yaml
std::ifstream fin("monsters.yaml");
YAML::Parser parser(fin);
YAML::Node doc;
parser.GetNextDocument(doc);
for(size_t i = 0; i < doc.size(); i++)
{
Monster monster;
doc[i] >> monster;
monsters.push_back(monster);
std::cout << monster.name << std::endl;
}
YAML::Emitter out;
//out << YAML::BeginSeq;
//for(size_t i = 0; i < monsters.size(); i++)
//{
// out << monsters[i];
//}
//out << YAML::EndSeq;
out << monsters; //stlemitter.h template interface
std::cout << out.c_str() << std::endl;
return 0;
}
YAML represents type information of native data structures with a simple identifier, called a tag. Global tags are URIs( Uniform Resource Identifiers (URI)) and hence globally unique across all applications. The “tag:” URI scheme is recommended for all global YAML tags. In contrast, local tags are specific to a single application. Local tags start with “!”, are not URIs and are not expected to be globally unique. YAML provides a “TAG” directive to make tag notation less verbose; it also offers easy migration from local to global tags. To ensure this, local tags are restricted to the URI character set and use URI character escaping.
YAML利用称为标签的简单标识符来表示本地数据结构的类型信息。 全局标记是URI,因此在所有应用程序中都是全局唯一的。 对于所有全局YAML标签,建议使用“tag:”URI方案。 相反,本地标签特定于单个应用程序。 本地标签以“!”开始,不是URI,并不是全局唯一的。 YAML提供了一个“TAG”指令,使标签符号不冗余; 它还提供从本地到全局标签的轻松迁移。 为了确保这一点,本地标签仅限于URI字符集,并使用URI字符转义。
YAML does not mandate any special relationship between different tags that begin with the same substring. Tags ending with URI fragments (containing “#”) are no exception; tags that share the same base URI but differ in their fragment part are considered to be different, independent tags. By convention, fragments are used to identify different “variants” of a tag, while “/” is used to define nested tag “namespace” hierarchies. However, this is merely a convention, and each tag may employ its own rules. For example, Perl tags may use “::” to express namespace hierarchies, Java tags may use “.”, etc.
YAML不要求以相同的子字符串开头的不同标签之间的任何特殊关系。 以URI片段结尾的标签(包含“#”)也不例外; 共享相同基本URI但在片段部分不同的标签被认为是不同的独立标签。 按照惯例,片段用于标识标签的不同“变体”,而“/”用于定义嵌套标签“命名空间”层次结构。 然而,这仅仅是一个惯例,每个标签都可以使用自己的规则。 例如,Perl标签可能使用“::”来表示命名空间层次结构,Java标签可能使用“。”等。
YAML tags are used to associate meta information with each node. In particular, each tag must specify the expected node kind (scalar, sequence, or mapping). Scalar tags must also provide a mechanism for converting formatted content to a canonical form for supporting equality testing. Furthermore, a tag may provide additional information such as the set of allowed content values for validation, a mechanism for tag resolution, or any other data that is applicable to all of the tag’s nodes.
YAML标签用于将元信息与每个节点相关联。 特别地,每个标签必须指定预期的节点种类(标量,序列或映射)。 标量标签还必须提供将格式化内容转换为规范表单以支持相似性测试的机制。 此外,标签可以提供附加信息,例如用于验证的允许内容值集合,标签解析机制或适用于所有标签节点的任何其他数据。
未完待续