如何在 yaml 文件中发出或写入地图的地图? C++

How to emit or write a map of maps in yaml file? c++

所以我有几个虚拟护目镜..每个都有不同的校准参数。我决定将这些参数保存到一个 yaml 文件中(作为配置文件).. 每个护目镜都有自己的 serial/identification 编号 ... 根据这个编号,我 select 使用哪一个。 如果眼镜没有预存信息。我校准它并将这些参数添加到文件中

所以现在我正在尝试写入如下所示的 yaml 文件:

Headset:
  IdentificationNumber: b630cc42-9a03-42da-a039-0e023cf5b090
  GyroOffset:
    GyroX:
      Value: -0.013776619
    GyroY:
      Value: -0.016475508
    GyroZ:
      Value: -0.0114268782

这就是我实际得到的:

Headset2:
  IdentificationNumber: b630cc42-9a03-42da-a039-0e023cf5b090
? GyroOffset:
    GyroX:
      Value: -0.013776619
  ? GyroY:
      Value: -0.016475508
  : GyroZ:
      Value: -0.0114268782

我不明白我做错了什么! .. 这是我写入 yaml 文件的函数:

void ParseInputDeviceYaml::addCalibrationToConfigFile(const char* identificationNumber, const float* in)
{
    try {
        std::ofstream updatedFile;
        updatedFile.open(m_filename.toStdString(), std::ios::app);

        std::map<std::string, std::string>                  IDNumber;
        std::map<std::string, std::map<std::string, float>> gyroXOffset;
        std::map<std::string, std::map<std::string, float>> gyroYOffset;
        std::map<std::string, std::map<std::string, float>> gyroZOffset;

        IDNumber["IdentificationNumber"] = identificationNumber;

        gyroXOffset["GyroX"]["Value"] = *in;
        gyroYOffset["GyroY"]["Value"] = *(in + 1);
        gyroZOffset["GyroZ"]["Value"] = *(in + 2);

        YAML::Emitter newNode;


        newNode << YAML::BeginMap;
        newNode << YAML::Key << "Headset2";
        newNode << YAML::Value << YAML::BeginMap << YAML::Key << "IdentificationNumber" << YAML::Value << identificationNumber << YAML::EndMap;
        newNode << YAML::BeginMap << YAML::Key << "GyroOffset" << YAML::Value << gyroXOffset << gyroYOffset << gyroZOffset << YAML::EndMap;
        newNode << YAML::EndMap;

        updatedFile << newNode.c_str() << "\n";

        updatedFile.close();
    } catch (std::exception& e) {
        LOG4CPLUS_FATAL(m_logger, e.what());
        throw std::runtime_error(QObject::tr("Writing gyroscope offsets ").toStdString());
    }
}

主要问题似乎是您建立了很多错误信息。我会尝试清除一些东西:

  • 是否使用序列与能否修改现有值或向文件添加新值完全无关。问题是您使用 std::ios::app 附加到文件,这将始终创建一个新条目。相反,您应该将文件加载到 YAML 节点,修改该节点的内容,然后写回整个节点。
  • 没有你给出的序列的 YAML 文件肯定不会做你认为的事情,因为你将 ? GyroOffset 放在与 Headset2: 相同的深度,使其成为 [=18= 的同级文件].另请注意,在同一映射中混合隐式 (foo:) 和显式 (? foo) 键是一种极端情况,可能会混淆某些实现。 YAML 文件可能看起来像这样:
Headset2:
  IdentificationNumber: b630cc42-9a03-42da-a039-0e023cf5b090
  GyroOffset:
    GyroX:
      Value: -0.012388126
    GyroY:
      Value: -0.0155748781
    GyroZ:
      Value: -0.0115196211

为了使您的代码更具可读性,我建议使用助手 classes 来访问您的值。假设上面的代码是整个 YAML 文件,它可能看起来像这样:

struct Value {
  YAML::Node data;
  // access existing node
  explicit Value(YAML::Node data): data(data) {
    assert(data.IsMapping());
  }
  // create new node
  explicit Value(float value) {
    data["Value"] = value;
  }

  float get() { return data["Value"].as<float>(); }
  void set(float value) { data["Value"] = value; }
};

struct GyroOffset {
  YAML::Node data;
  explicit GyroOffset(YAML::Node data): data(data) {
    assert(data.IsMapping());
  }
  GyroOffset(float x, float y, float z) {
    data["GyroX"] = Value(x).data;
    data["GyroY"] = Value(y).data;
    data["GyroZ"] = Value(z).data;
  }
  Value gyroX() { return Value(data["GyroX"]); }
  Value gyroX() { return Value(data["GyroY"]); }
  Value gyroZ() { return Value(data["GyroZ"]); }
};

struct Headset {
  YAML::Node data;
  Headset(YAML::Node data): data(data) {
    assert(data.IsMapping());
  }
  Headset(const char *id) {
    data["IdentificationNumber"] = id;
    // initialize with zero values
    data["GyroOffset"] = GyroOffset(0, 0, 0).data;
  }

  std::string id() { return data["IdentificationNumber"].as<std::string>(); }
  void setId(const char *value) { data["IdentificationNumber"] = value; }

  GyroOffset gyroOffset() { return GyroOffset(data["GyroOffset"]); }
}

现在,找到给定标识号的 GyroOffset 看起来像这样(我展示了一个简单的函数,因为我不知道你的 class' 字段,因为你没有展示它们):

// write found values to output of found
bool findHedasetGyroOffset(Yaml::Node &input /* the file as shown above */, const char *id, GyroOffset &output) {
  for (auto it = input.begin(); it != input.end(); ++it) {
    Headset hs(it->second);
    if (hs.id() == id) {
      output = hs.gyroOffset();
      return true;
    }
  }
  return false;
}

由于 YAML::Node 基本上是一个引用,当您更改返回的 GyroOffset 中的值时,原始数据会发生变化。然后您可以将根节点写回到文件中(而不是追加它)并有一个更新的文件。

添加新耳机如下所示:

void addCalibrationToConfigFile(Yaml::Node &file, const char* identificationNumber, const float* in) {
  Headset newHs(identificationNumber);
  auto go = newHs.gyroOffset();
  go.gyroX().set(*in);
  go.gyroY().set(*(in + 1));
  go.gyroZ().set(*(in + 2));
  // note that this will overwrite an existing Headset2
  file["Headset2"] = newHs.data;
}

虽然我尝试遵循您显示的结构,但我感觉映射中的实际键不应该是 Headset2,而是 IdentificationNumber:

b630cc42-9a03-42da-a039-0e023cf5b090:
  Name: Headset2
  GyroOffset:
    GyroX:
      Value: -0.012388126
    GyroY:
      Value: -0.0155748781
    GyroZ:
      Value: -0.0115196211

由于您是根据 ID 进行查找的,所以这会更有意义。此外,创建一个新的配置实际上是有效的(目前,由于硬编码的 "Headset2" 值,它总是会覆盖该耳机(如果存在)。

当心,我写的代码只是为了演示,并没有测试它;可能有错误。