Search code examples
yaml-cpp

How to access yaml with complex keys


The file test.yaml .....

   ---
   map:
        ? [L, itsy] : ISO_LOW_ITSY(out, in, ctrl) 
        ? [L, bitsy] : ISO_LOW_BITSY(out, in, ctrl) 
        ? [L, spider] : ISO_LOW_SPIDER(out, in, ctrl) 
        ? [H, ANY] : ISO_HIGH(out, in, ctrl)

What command can I use to access one of these with yaml-cpp. I can access the map as a whole, but not individual elements.

Here's what I am trying:

    YAML::Node doc = YAML::LoadFile("test.yaml");
    std::cout << "A:" << doc["mapping"] << std::endl;
    std::cout << "LS1:" << doc["mapping"]["[L, spider]"] << std::endl;
    std::cout << "LS2:" << doc["mapping"]["L", "spider"] << std::endl;

Here are my results:

    A:? ? - L
          - itsy
 : ISO_LOW_ITSY(out, in, ctrl)
: ~
? ? - L
    - bitsy
  : ISO_LOW_BITSY(out, in, ctrl)
: ~
? ? - L
    - spider
  : ISO_LOW_SPIDER(out, in, ctrl)
: ~
? ? - H
    - ANY
  : ISO_HIGH(out, in, ctrl)
: ~
LS1:
LS2:

If this is not yet possible in yaml-cpp, I would like to know that too.


Solution

  • You have to define a type that matches your key. For example, if your key is a sequence of two scalars:

    struct Key {
      std::string a, b;
    
      Key(std::string A="", std::string B=""): a(A), b(B) {}
    
      bool operator==(const Key& rhs) const {
        return a == rhs.a && b == rhs.b;
      }
    };
    
    namespace YAML {
      template<>
      struct convert<Key> {
        static Node encode(const Key& rhs) {
          Node node;
          node.push_back(rhs.a);
          node.push_back(rhs.b);
          return node;
        }
    
        static bool decode(const Node& node, Key& rhs) {
          if(!node.IsSequence() || node.size() != 2)
            return false;
    
          rhs.a = node[0].as<std::string>();
          rhs.b = node[1].as<std::string>();
          return true;
        }
      };
    }
    

    Then, if your YAML file is

    ? [foo, bar]
    : some value
    

    You could write:

    YAML::Node doc = YAML::LoadFile("test.yaml");
    std::cout << doc[Key("foo", "bar")];     // prints "some value"
    

    Note:

    I think your YAML doesn't do what you intended. In block context, an explicit key/value pair must be on separate lines. In other words, you should do

    ? [L, itsy]
    : ISO_LOW_ITSY(out, in, ctrl)
    

    and not

    ? [L, itsy] : ISO_LOW_ITSY(out, in, ctrl)
    

    The latter makes it a single key, with an (implicit) null value; i.e., it's the same as

    ? [L, itsy] : ISO_LOW_ITSY(out, in, ctrl)
    : ~
    

    (You can see this by how yaml-cpp outputs your example.) See the relevant area in the spec.