Skip to content

YAML

Abstract

The SSTD YAML parser. sstd::yaml_ seriese functions are the SSTD YAML parser set and are used along with the sstd::terp class. A instance of the sstd::terp class operates like a interpreter object. And the user can treat YAML file through the sstd::terp object.

SSTD YAML パーサ.sstd::yaml_ 系の関数は SSTD の yaml パーサーセットであり,sstd::terp クラスとともに使用されます. sstd::terp クラスのインスタンスは,インタープリタ (interpreter) のオブジェクトのように動作します. ユーザは sstd::terp オブジェクトを通して,YAML ファイルを扱うことができます.

Header file

namespace sstd{
    bool yaml_load     (           sstd::terp::var & ret_yml,  const        char* s);
    bool yaml_load     (           sstd::terp::var & ret_yml,  const std::string& s);
    bool yaml_load_all(std::vector<sstd::terp::var>& ret_vYml, const        char* s);
    bool yaml_load_all(std::vector<sstd::terp::var>& ret_vYml, const std::string& s);

    bool yaml_load    (            sstd::terp::var & ret_yml,  sstd::file& fp);
    bool yaml_load_all(std::vector<sstd::terp::var>& ret_vYml, sstd::file& fp);
}

Description

Function name Description
yaml_load(var&, c*/s&) reads YAML string and converts to sstd::terp::var object.
YAML 文字列を読み取り sstd::terp::var オブジェクトに変換します.
yaml_load(var&, file&) reads YAML string through the sstd::file instance opened by the sstd::file::fopen() instance method. After that, this function converts to the YAML string to sstd::terp::var object.
sstd::file::fopen() インスタンスメソッドで開かれた sstd::file インスタンスを介して YAML テキストを読み取ります.その後,YAML 文字列を sstd::terp::var オブジェクトに変換します.
yaml_load_all() is extended version of yaml_load() and supports --- YAML command.
yaml_load() 関数を拡張したバージョンで,--- YAML コマンドをサポートしています.

Usage

yaml_load(var&, c*/s&)

  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        std::string s = R"(
    - a1
    - k1: v1
    )";
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, s)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(yml);
    }
    
  • Execution result
    yml = ["a1" {"k1": "v1"}]
    

yaml_load(var&, file&)

  • example.yaml
    - a1
    - k1: v1
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        std::string path = "./example.yaml";
        sstd::file fp; if(!fp.fopen(path, "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(yml);
    }
    
  • Execution result
    yml = ["a1" {"k1": "v1"}]
    

yaml_load_all(var&, c*/s&)

  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        std::string s = R"(
    - a1
    - k1: v1
    ---
    - a2
    - k2: v2
    ---
    - a3
    - k3: v3
    )";
    
        std::vector<sstd::terp::var> v_yml;
        if(!sstd::yaml_load_all(v_yml, s)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(v_yml);
    }
    
  • Execution result
    v_yml = [["a1" {"k1": "v1"}] ["a2" {"k2": "v2"}] ["a3" {"k3": "v3"}]]
    

yaml_load_all(var&, file&)

  • example.yaml
    - a1
    - k1: v1
    ---
    - a2
    - k2: v2
    ---
    - a3
    - k3: v3
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        std::string path = "./example.yaml";
        sstd::file fp; if(!fp.fopen(path, "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        std::vector<sstd::terp::var> v_yml;
        if(!sstd::yaml_load_all(v_yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(v_yml);
    }
    
  • Execution result
    v_yml = [["a1" {"k1": "v1"}] ["a2" {"k2": "v2"}] ["a3" {"k3": "v3"}]]
    

Appendix

YAML notation and support status / YAML 記法とサポート状況

alias

Not supported.

anchor

Not supported.

data type specification

Not supported.

ex:
- !str abc
- !str 123
- !pairs
  - k1: v1
  - k2: v2

comment

  • example.yaml
    - a
    #- b
    - c
    - k1: v1
    #  k2: v2
      k3: v3
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        sstd::file fp; if(!fp.fopen("./example.yaml", "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(yml);
    }
    
  • Execution result
    yml = ["a" "c" {"k3": "v3", "k1": "v1"}]
    

end of YAML ('...')

Using '...' notation enables to stop reading the YAML file.

'...' 記法の使用で YAML ファイルの読み込みを終了できます.

  • example.yaml
    - a
    - b
    ...
    - c
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        sstd::file fp; if(!fp.fopen("./example.yaml", "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(yml);
    }
    
  • Execution result
    yml = ["a" "b"]
    

flow style notation

  • example.yaml
    [a, b, c, {k1: v1}]
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        sstd::file fp; if(!fp.fopen("./example.yaml", "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(yml);
    }
    
  • Execution result
    yml = ["a" "b" "c" {"k1": "v1"}]
    

hash / ハッシュ

  • example.yaml
    k1: v1
    k2: v2
    k3:
      k31: v31
      k32: v32
      k33: v33
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        sstd::file fp; if(!fp.fopen("./example.yaml", "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(yml);
    }
    
  • Execution result
    yml = {"k3": {"k33": "v33", "k31": "v31", "k32": "v32"}, "k1": "v1", "k2": "v2"}
    

list / 配列

  • example.yaml
    - a1
    - b1
    - c1
    -
      - c12
      - c12
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        sstd::file fp; if(!fp.fopen("./example.yaml", "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(yml);
    }
    
  • Execution result
    yml = ["a1" "b1" "c1" ["c12" "c12"]]
    

multiple line string by '|' / 複数行の文字列 ('|')

Using the pipe sign ('|') enables to read the string which contains the line feed code.

  • '|' reads the string with the line feed code.
  • '|+' reads the string with the line feed code and the last line feeds to the next item.
  • '|-' reads the string with the line feed code, except last line.

パイプ記号 ('|') の使用で改行コードを含む文字列を読み込めます.

  • '|' は改行のある文字列を読み込みます.
  • '|+' は改行のある文字列と最終行は次の項目までの改行を読み込みます.
  • '|-' は改行のある文字列を読み込みますが,最終行の改行は取り除かれます.

Note / 注意:

The YAML standard does NOT treat '#' in the Block Chomping Indicator ('|') as a comment, but treats as a text.

YAML の規格では,Block Chomping Indicator ('|') 中に含まれる '#' をコメントとして取り扱わず,テキストとして取り扱います.

Ref: 8.1.1.2. Block Chomping Indicator - The YAML Standard

  • example.yaml
    - |
      s1
      s2
      s3 # contains the line feed / 改行を含める
    
    
    - |+
      s_plus1
      s_plus2
      s_plus3 # contains the last line feed(s) to the next item / 最終行と次の項目までの改行を含める
    
    
    - |-
      s_minus1
      s_minus2
      s_minus3 # not contains the last line feed / 最終行の改行を含めない
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        sstd::file fp; if(!fp.fopen("./example.yaml", "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(yml);
    }
    
  • Execution result
    yml = ["s1
    s2
    s3 # contains the line feed / 改行を含める
    " "s_plus1
    s_plus2
    s_plus3 # contains the last line feed(s) to the next item / 最終行と次の項目までの改行を含める
    
    
    " "s_minus1
    s_minus2
    s_minus3 # not contains the last line feed / 最終行の改行を含めない"]
    

multiple line string by '|N' / 複数行の文字列 ('|N')

Using the pipe sign with number ('|N') enables to indicate the width of indent.

パイプ記号と数値を組み合わせ ('|N') でインデント幅を指示できます.

  • example.yaml
    - |2
        s1
        s2
        s3 # contains the line feed / 改行を含める
    
    
    - |+2
        s_plus1
        s_plus2
        s_plus3 # contains the last line feed(s) to the next item / 最終行と次の項目までの改行を含める
    
    
    - |-2
        s_minus1
        s_minus2
        s_minus3 # not contains the last line feed / 最終行の改行を含めない
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        sstd::file fp; if(!fp.fopen("./example.yaml", "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(yml);
    }
    
  • Execution result
    yml = ["  s1
      s2
      s3 # contains the line feed / 改行を含める
    " "  s_plus1
      s_plus2
      s_plus3 # contains the last line feed(s) to the next item / 最終行と次の項目までの改行を含める
    
    
    " "  s_minus1
      s_minus2
      s_minus3 # not contains the last line feed / 最終行の改行を含めない"]
    

multiple line string by '>' / 複数行の文字列 ('>')

Using the greater-than sign ('>') enables to read the string which contains the line feed code. At this time, the line feed code(s) are converted to the space(s) (' ').

  • '>' reads the string with line feed code, and converts line feed code(s) to the space(s) (' ').
  • '>+' reads the string with line feed code, and converts line feed code(s) to space (' '), while keeping the line feed code(s) between the last line and next item.
  • '>-' reads the string with line feed code, and converts line feed code(s) to space (' '), except the line feed code at the last line.

大なり記号 ('>') の使用で改行コードを含む文字列を読み込めます.このとき,改行コードはスペース (' ') に変換されます.

  • '>' は改行コードのある文字列を読み込み,改行コードをスペース (' ') に変換します.
  • '>+' は改行コードのある文字列を読み込み,改行コードをスペース (' ') に変換します.ただし,最終行から次の項目までの改行を保持します.
  • '>-' は改行コードのある文字列を読み込み,改行コードをスペース (' ') に変換します.ただし,最終行の改行を無視します.

Note / 注意:

The YAML standard does NOT treat '#' in the Block Chomping Indicator ('|') as a comment, but treats as a text.

YAML の規格では,Block Chomping Indicator ('|') 中に含まれる '#' をコメントとして取り扱わず,テキストとして取り扱います.

Ref: 8.1.1.2. Block Chomping Indicator - The YAML Standard

  • example.yaml
    - >
      s1
      s2
      s3 # contains the line feed / 改行を含める
    
    
    - >+
      s_plus1
      s_plus2
      s_plus3 # contains the last line feed(s) to the next item / 最終行と次の項目までの改行を含める
    
    
    - >-
      s_minus1
      s_minus2
      s_minus3 # not contains the last line feed / 最終行の改行を含めない
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        sstd::file fp; if(!fp.fopen("./example.yaml", "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(yml);
    }
    
  • Execution result
    yml = ["s1 s2 s3 # contains the line feed / 改行を含める
    " "s_plus1 s_plus2 s_plus3 # contains the last line feed(s) to the next item / 最終行と次の項目までの改行を含める
    
    
    " "s_minus1 s_minus2 s_minus3 # not contains the last line feed / 最終行の改行を含めない"]
    

multiple line string by '>N' / 複数行の文字列 ('>N')

Using the greater-than with number ('>N') enables to indicate the width of indent.

大なり記号と数値を組み合わせ ('>N') でインデント幅を指示できます.

  • example.yaml
    - >2
        s1
        s2
        s3 # contains the line feed / 改行を含める
    
    
    - >+2
        s_plus1
        s_plus2
        s_plus3 # contains the last line feed(s) to the next item / 最終行と次の項目までの改行を含める
    
    
    - >-2
        s_minus1
        s_minus2
        s_minus3 # not contains the last line feed / 最終行の改行を含めない
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        sstd::file fp; if(!fp.fopen("./example.yaml", "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(yml);
    }
    
  • Execution result
    yml = ["  s1
      s2
      s3 # contains the line feed / 改行を含める
    " "  s_plus1
      s_plus2
      s_plus3 # contains the last line feed(s) to the next item / 最終行と次の項目までの改行を含める
    
    
    " "  s_minus1
      s_minus2
      s_minus3 # not contains the last line feed / 最終行の改行を含めない"]
    

quotes / 引用符

  • example.yaml
    - ' a 1 '
    - " b 1 "
    - ' k 1 ': ' v 1 '
    - " k 2 ": " v 2 "
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        sstd::file fp; if(!fp.fopen("./example.yaml", "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(yml);
    }
    
  • Execution result
    yml = [" a 1 " " b 1 " {" k 1 ": " v 1 "} {" k 2 ": " v 2 "}]
    

Example of setting file loading

sample1

  • example.yaml
    users:
      - name: user001
        email: user001@example.com
        public-keys:
          - ssh-ed25519 XXXX user001-1@XXX.XXX
          - ssh-ed25519 XXXX user001-2@XXX.XXX
      - name: user002
        email: user002@example.com
        public-keys:
          - ssh-ed25519 XXXX user002@XXX.XXX
      - name: user003
        email: user003@example.com
        public-keys:
          - ssh-ed25519 XXXX user003@XXX.XXX
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    struct usr{
        std::string usr_name;
        std::string email;
        std::vector<std::string> v_public_key;
    };
    
    bool usrObj2usrStruct(struct usr& ret, const sstd::terp::var& obj){
        if(!sstd::terp::isHash( obj )){ return false; }
        if(!(obj.find("name"       )!=obj.end())){ return false; }
        if(!(obj.find("email"      )!=obj.end())){ return false; }
        if(!(obj.find("public-keys")!=obj.end())){ return false; }
    
        ret.usr_name = obj["name" ].to<std::string>();
        ret.email    = obj["email"].to<std::string>();
    
        for(uint ip=0; ip<obj["public-keys"].size(); ++ip){
            ret.v_public_key.push_back( obj["public-keys"][ip].to<std::string>() );
        }
    
        return true;
    }
    bool usrObj2usrStruct(std::vector<struct usr>& ret, const sstd::terp::var& v_obj){
        std::vector<struct usr> v;
        for(uint i=0; i<v_obj.size(); ++i){
            struct usr tmp; if(! usrObj2usrStruct(tmp, v_obj[i]) ){ return false; }
            ret.push_back( tmp );
        }
        return true;
    }
    
    int main(){
        sstd::file fp; if(!fp.fopen("./example.yaml", "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
    
        std::vector<struct usr> v_usr; if(!usrObj2usrStruct(v_usr, yml["users"])){ sstd::pdbg_err("Parsing the yaml object is failed."); };
    
        for(uint i=0; i<v_usr.size(); ++i){
            printf("usr_name: %s\n", v_usr[i].usr_name.c_str());
            printf("email: %s\n",    v_usr[i].email.c_str()   );
            printf("public_keys: [");
            for(uint ip=0; ip<v_usr[i].v_public_key.size(); ++ip){
                printf(" \"%s\"", v_usr[i].v_public_key[ip].c_str());
            }
            printf(" ]\n");
            printf("\n");
        }
    }
    
  • Execution result
    usr_name: user001
    email: user001@example.com
    public_keys: [ "ssh-ed25519 XXXX user001-1@XXX.XXX" "ssh-ed25519 XXXX user001-2@XXX.XXX" ]
    
    usr_name: user002
    email: user002@example.com
    public_keys: [ "ssh-ed25519 XXXX user002@XXX.XXX" ]
    
    usr_name: user003
    email: user003@example.com
    public_keys: [ "ssh-ed25519 XXXX user003@XXX.XXX" ]
    

sample2

  • example.yaml
    parameter:
      lib_url: "https://github.com/admiswalker/SubStandardLibrary-SSTD-/archive/refs/heads/master.zip"
      max_retry: 10
      wait_time_sec: 10
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        sstd::file fp; if(!fp.fopen("./example.yaml", "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
    
        std::string lib_url = yml["parameter"]["lib_url"].to<std::string>();
        uint max_retry      = yml["parameter"]["max_retry"].to<uint>();
        uint wait_time_sec  = yml["parameter"]["wait_time_sec"].to<uint>();
        sstd::printn( lib_url       );
        sstd::printn( max_retry     );
        sstd::printn( wait_time_sec );
    }
    
  • Execution result
    lib_url = "https://github.com/admiswalker/SubStandardLibrary-SSTD-/archive/refs/heads/master.zip"
    max_retry = 10
    wait_time_sec = 10
    

sample2: setting file for some Server

  • example.yaml
    #cloud-config
    cloud_final_modules:
      - [users-groups, always]
    users: # run by "users-groups" option
      - default
      - name: user_name
        groups: [wheel]
        sudo: ["ALL=(ALL) NOPASSWD:ALL"]
        shell: /bin/bash
        ssh-authorized-keys:
          - ssh-ed25519 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX user_name@user_name.XXX.XXX
    runcmd: # run by "scripts-user" option
      - echo ""
      - echo ""
      - echo "--- begin --- example of run command -------------------------------------------"
      - echo "Hello cloud-config / runcmd"
      - echo "------------------------------------------------------------------------ end ---"
      - echo ""
      - echo ""
    
  • main.cpp
    #include <sstd/sstd.hpp>
    
    int main(){
        sstd::file fp; if(!fp.fopen("./example.yaml", "r")){ sstd::pdbg_err("fopen() is failed.\n"); return 0; }
    
        sstd::terp::var yml;
        if(!sstd::yaml_load(yml, fp)){ sstd::pdbg_err("yaml_load() is failed.\n"); return 0; }
        sstd::printn(yml);
    }
    
  • Execution result
    yml = {"runcmd": ["echo """ "echo """ "echo "--- begin --- example of run command -------------------------------------------"" "echo "Hello cloud-config / runcmd"" "echo "------------------------------------------------------------------------ end ---"" "echo """ "echo """], "cloud_final_modules": [["users-groups" "always"]], "users": ["default" {"ssh-authorized-keys": ["ssh-ed25519 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX user_name@user_name.XXX.XXX"], "shell": "/bin/bash", "sudo": [""ALL=(ALL) NOPASSWD:ALL""], "name": "user_name", "groups": ["wheel"]}]}
    

Implementation